当前位置: 首页 > article >正文

SpringBoot项目实现登录——集成JWT令牌和验证码的登录业务

目录

前言

一、初步认识JWT令牌

二、利用JWT令牌实现登录功能 

1.配置登录拦截器:

2.实现后端的登录接口

三、在登录中添加验证码功能

点此查看:完整的,附带验证码和JWT令牌验证功能的登录流程,完整代码


前言

        在我们的项目中,如何防止用户在未登录的情况下就去访问网站内其他的资源呢?

答:

        通常我们使用JWT令牌(token)来实现一个功能完善的登录模块,在用户登录成功后,服务器会返回给前端一串加密过的长字符串作为令牌(token),下次前端再进行请求时带上该令牌作为参数,后端服务器识别后就会允许前端访问其它站点。

一、初步认识JWT令牌

JWT(全称:Json Web Token)是我们Web开发中最常用的令牌规范,

1. 令牌包含的基本功能:

  • 承载业务数据:令牌字符串中应该包含用户的基本信息或其他所需数据,方便后端识别;

  • 具有防篡改、防伪功能,保证信息的合法性和有效性

 

2. JWT字符串令牌的组成

一串令牌有三部分组成:Header(头)、Payload(有效载荷)、Signature(签名)

  • 第一部分:Header(头),记录令牌类型、签名算法等。例如:{"alg":HS256”,"type":"JWT”}
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。例如:{“id":"1”,“userame”:"Tom”)
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性,将header、payioad,并加入指定秘钥,通过指定签名算法计算而来,

 具体情况如下图所示:

一定要注意的是:令牌原本是Json格式的数据,是通过一种常见的编码方式(Base64编码),编码成了一串字符串,因此在第二部分Payload(有效载荷)中不要存放一些私密数据,因为他人通过反编码就可以得到这部分数据。

3. 生成JWT令牌

①引入依赖

<!--    引入java-jwt令牌的相关依赖    -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.4.0</version>
</dependency>
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <scope>test</scope>
</dependency>

②利用JWT .create()方法进行生成

@Test
    public void testCreateJWT(){
        //创建一个map集合作为载荷
        Map<String, Object> claims = new HashMap<>();
        //向载荷中添加一些令牌需要携带的信息
        claims.put("id",1);
        claims.put("username","大码农123");
        //生成JWT令牌
        String token = JWT.create()
                .withClaim("user",claims)//添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))//设置到期时间
                .sign(Algorithm.HMAC256("yzx_zxx"));//设置签名部分加密所用的算法,算法中要自定义加密密钥
        System.out.println(token);
    }

 输出结果:

token令牌:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuWkp-eggeWGnDEyMyJ9LCJleHAiOjE3MzE3MjAwMzF9.gEep6Ro_0B2uEFvNeyeGzXmZhiXfifFiFPsGAPW5E1g


 

4.验证JWT令牌

代码如下:

@Test
    //验证token
    public void parseToken(){
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
                "eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuWkp-eggeWGnDEyMyJ9LCJleHAiOjE3MzE3MjAyMzV9." +
                "vXCQ9cl4_aMpEUI2C4HB7LmGlP4zvKxRNR95ltwW6U8";
        //用JWT生成一个token解析对象,并传入指定加密算法和密钥
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("yzx_zxx")).build();

        //用刚刚生成的解析对象去解析token,生成一个解析后的JWT token的对象
        DecodedJWT decodedJWT = jwtVerifier.verify(token);

        //通过解析后的JWT对象,可以获取token中有效载荷部分的信息
        Map<String, Claim> claims = decodedJWT.getClaims();
        //此处的claims是token中所有claim的集合,包含了claim01,claim02,claim03....
        System.out.println(claims.get("user"));
    }

输出结果:{"id":1,"username":"大码农123"}

若令牌已经失效,则报错如下:

com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on 2024-08-10T21:19:51Z.

注意事项:

  •  JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的
  • 如果JWT令牌解析校验时报错,则说明JWT令牌被篡改 或 失效了,令牌非法。

在上述token验证的过程中,验证失败的三种情况:

  • 第一种:token字符串中的Header(头部)和Payload(有效载荷)部分如果被篡改了,则会验证失败,抛出如下异常:
//头部被修改
com.auth0.jwt.exceptions.JWTDecodeException: The string {"alg":"HS256","typ":"JWT"}' doesn't have a valid JSON format.

//有效载荷被修改
com.auth0.jwt.exceptions.JWTDecodeException: The string "user":{"id":1,"username":"大码农123"},"exp":1723324791}' doesn't have a valid JSON format.
  • 第二种:生成token时设置了密钥,如果在验证token时密钥输入不正确,或者Signature(签名)部分被篡改时,会验证失败,抛出如下异常:
    //验证token时密钥输入错误
    com.auth0.jwt.exceptions.SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256
  •  第三种:当token的时效到期时,也会验证失败,抛出如下异常:
    //token过期
    com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on 2024-08-10T11:32:10Z.

二、利用JWT令牌实现登录功能 

1.配置登录拦截器:

拦截器的作用:拦截所有除用户登录以外的请求,若用户携带token并验证成功后则放行,否则提示用户先进行登录;

下面在IDEA中演示,如何配置登录拦截器:

(1)先创建一个interceptor包,在该包中创建一个登录拦截器LoginInterceptor,用@Component注解将其注入到IOC容器中;

第一种写法:从前端请求的请求头header中获取token并验证

(该写法是在后端登录接口中,将JWT生成的token信息直接返回给前端,再由前端添加到请求头header中)

代码如下:

@Component//通过该注解,将拦截器注入到IOC容器中
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /*通过HttpServletRequest的实例request,可以访问到所有的前端请求;
        1.再调用request中的getHeader()方法访问前端请求中的请求头
        2.请求头中"Authorization"关键字对应的是token字符串
        */
        //获取前端请求中的token
        String token = request.getHeader("Authorization");
        //验证token
        try {
            Map<String, Object> claims = JWTUtils.parseToken(token);
            //如果成功获得token中的claims信息,说明token验证成功,返回true(放行,用户已登陆)
            return true;
        } catch (Exception e) {
            //如果捕捉到异常,说明token验证失败,因此无法获得其中的claims信息
            //将响应状态码设置成401,并返回false(不放行,用户未登陆)
            response.setStatus(401);
            return false;
        }
    }
}
第二种写法:从前端请求的cookie中获取token并验证

(该写法是在后端登录接口中,将JWT生成的token信息添加到cookie中,然后将cookie添加进HttpServletResponse响应体)

代码如下:

/**
 * 拦截器
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 除了登录请求以外的其他请求都要进行过滤
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for (Cookie cookie:cookies){
                if("token".equals(cookie.getName())){
                    String userToken = cookie.getValue();
                    if(!StringUtils.hasText(userToken)){
                        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                    }
                    //解析token看看是否成功
                    try {
                        Map<String,Object> claims = JWTUtils.parseToken(userToken);

                        //将业务数据存入到ThreadLocal中
                       ThreadLocalUtil.set(claims);
                        //如果,get不到则会报错,然后被catch抓取
                    }catch (Exception e){
                        //e.printStackTrace();
                        System.out.println("token信息出错");
                        return false;
                    }
                    return true;  //放行
                }
            }
        }
        return false;
    }

}
那上述两种写法各有什么优缺点呢?
  • 添加到请求头(Header)的优点:

        ①安全性相对较高:因为 HTTP 请求头在正常情况下不会被浏览器等客户端自动处理(与 Cookie 不同,Cookie 会被浏览器自动添加到请求中),这就减少了跨站脚本攻击(XSS)获取 token 的风险。

        ②适合前后端分离架构:在前后端分离的应用中,前端通过 JavaScript 发送请求时可以方便地在请求头中设置 token。例如,在使用 Axios 库的 Vue.js 项目中,设置请求头携带 token 非常方便,像 Axios 可以通过axios.defaults.headers.common['Authorization'] = token这样的方式统一为所有请求添加包含 token 的请求头。

  • 添加到请求头(Header)的缺点

         跨域问题可能更复杂:当涉及跨域请求时,浏览器会限制对请求头的访问。这时需要后端进行额外的配置,来允许携带特定的请求头。否则浏览器会阻止带有 token 的跨域请求。

  • 添加到 Cookie 的优点

        兼容性好:几乎所有的浏览器都能自动处理 Cookie。对于传统的 Web 应用,不需要额外的客户端代码来处理 token 的传递。这使得开发过程更加简单,尤其是对于那些没有使用复杂前端框架的应用。

  • 添加到 Cookie 的缺点

        安全性风险:容易受到跨站脚本攻击(XSS)。例如,在一个存在漏洞的 Web 页面中,攻击者注入的脚本可以通过document.cookie获取所有的 Cookie 信息,包括 token。

(2)通过配置类来配置登录拦截器

建一个config包,在该包定义一个WebConfig配置类中,用@Configuration注解标明该类是一个配置类,作用是配置登录拦截器

配置类中的代码如下:

  • addPathPatterns("/**")方法中配置要拦截的请求,/**代表所有请求
  • excludePathPatterns()方法中,指定那些请求不要拦截,如登录、静态资源等请求通常不拦截
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    /**
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)//添加拦截器
                .addPathPatterns("/**")  //配置要拦截的路径
                .excludePathPatterns("/login/**","/static/**","/templates/**","/");//配置不拦截的路径
    }
}

 至此,在SpringBoot项目中,一个登录拦截器就配置完成了;那么接下来我们演示如何实现登录的接口;

2.实现后端的登录接口

(1)借助JWTUtils工具类

首先,我们把生成JWT令牌和验证JWT令牌这两段代码封装成一个工具类,方便我们使用

JWTUtis工具类:

package com.yzx.core.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.Date;
import java.util.Map;


public class JWTUtils {

    private static final String KEY = "yzx_zxx";

    //接受用户信息,返回生成的token
    public static String getToken(Map<String, Object> claims){
        return JWT.create()
                .withClaim("claims",claims)
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))//设置有效期
                .sign(Algorithm.HMAC256(KEY));
    }

    //接收并验证token,并返回token所携带的信息
    public static Map<String,Object> parseToken(String token){
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();

    }
}

        这样做的好处:在一个应用程序中,可能有多个地方需要生成或验证 JWT 令牌。这样我们代码复用性就会提高了;如果 JWT 令牌的生成或验证逻辑需要修改,那么我们直接修改该工具类即可。

(2)在LoginController中实现登录的接口代码:
@PostMapping("/loginManage")
    @ResponseBody
    public Result<String> login(String username,String password, HttpServletRequest request, HttpServletResponse response){

        HttpSession session = request.getSession();
        
        User loginUser = userDao.findByUsername(username);
        if (loginUser == null){
            return Result.error("用户不存在!");
        }


        if (password.equals(loginUser.getPassword())){
            Map<String, Object> claims = new HashMap();
            claims.put("email",loginUser.getEmail());
            claims.put("id",loginUser.getId());


            String token = JWTUtils.getToken(claims);
            //将token信息设置如cookie当中
            Cookie cookie = new Cookie("token",token)
            cookie.setPath("/");   //设置浏览器的访问路径
            cookie.setMaxAge(36000); //设置cookie的过期时间
            response.addCookie(cookie);
            return Result.success("登录成功");
        }else{
            return Result.error("密码错误!");
        }
    }

       (其中的User是用来封装用户信息的普通pojo类。 )

 注意:上述代码,演示的是将JWT生成的token信息添加到cookie中,然后将cookie添加进HttpServletResponse响应体,对应的是拦截器的第二种写法:从前端请求的cookie中获取token并验证;    

(大家可以自己探索一下,将token信息返回给前端,然后添加进请求头的写法如何实现)

三、在登录中添加验证码功能

        上面,我们已经完整的完成了一个带有 JWT 令牌验证的登录功能;在实际应用场景中,为了进一步增强登录的安全性,防止恶意攻击,如暴力破解用户密码等情况的发生,我们需要在登录流程中添加验证码功能。

1.验证码生成方式选择

        我们可以采用多种方式来生成验证码。比较常见且简单的的方法是使用图形验证码,通过生成包含随机数字和字母组合的图片来实现;

实现图形验证码的工具类:VerifyCodeUtil 

(完整代码资源,附在文章开头,点击可下载,大家也可自行复制下面的代码)

package com.yzx.springbootdemo.utils;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 	生成验证码的工具类
 * @author 王
 *
 */
public class VerifyCode {
	private int w = 70;//设置缓冲区的宽
	private int h = 35;//设置缓冲区的宽
	private Random r = new Random();
	 {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"}
	private String[] fontNames  = {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"};
	//源
	private String codes  = "123456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
	// 背景颜色
	private Color bgColor  = new Color(255, 255, 255);
	// 保存随机生成的图片当中的内容。
	private String text ;

	// 随机生成颜色
	private Color randomColor () {
		int red = r.nextInt(150);
		int green = r.nextInt(150);
		int blue = r.nextInt(150);
		return new Color(red, green, blue);
	}

	// 随机生成字体
	private Font randomFont () {
		int index = r.nextInt(fontNames.length);
		String fontName = fontNames[index];//根据随机的索引,获取随机字体
		int style = r.nextInt(4);//0,1,2,3, 0:没有任何样式,1,加粗,2,斜体,3,加粗和斜体  PLAIN(0)、BOLD(1)、ITALIC(2) 或 BOLD+ITALIC(3)。
		int size = r.nextInt(5) + 24; //随机生成字号
		return new Font(fontName, style, size);
	}

	// 画干扰线
	private void drawLine (BufferedImage image) {
		int num  = 3;//花三条干扰线
		Graphics2D g2 = (Graphics2D)image.getGraphics();
		for(int i = 0; i < num; i++) {
			int x1 = r.nextInt(w);
			int y1 = r.nextInt(h);
			int x2 = r.nextInt(w);
			int y2 = r.nextInt(h);
			g2.setStroke(new BasicStroke(1.5F));
			g2.setColor(Color.BLUE); //给干扰线设置了颜色
			g2.drawLine(x1, y1, x2, y2);//划线
		}
	}

	//随机生成字符
	private char randomChar () {
		int index = r.nextInt(codes.length());
		return codes.charAt(index);
	}

	// 得到一个缓冲区
	private BufferedImage createImage () {
		// 获取一个缓冲区
		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		// 得到一个画笔
		Graphics2D g2 = (Graphics2D)image.getGraphics();
		// 设置画笔的颜色 白颜色
		g2.setColor(this.bgColor);
		// 填充图片的缓冲区。
		g2.fillRect(0, 0, w, h);
		// 将缓冲区返回。
		return image;
	}

	// 调用该方法,可以得到验证码
	public BufferedImage getImage () {
		BufferedImage image = createImage();//创建图片的缓冲区
		Graphics2D g2 = (Graphics2D)image.getGraphics();//得到绘制环境(画笔)
		StringBuilder sb = new StringBuilder();//定义一个容器,用来装在生成的验证码
		//向图片当中画四个字符
		for(int i = 0; i < 4; i++)  {//循环四次,每次生成一个字符
			String s = randomChar() + "";//随机成成一个字符
			sb.append(s); //将生成的字符放在缓冲区
			float x = i * 1.0F * w / 4; //设置当前字符的x轴坐标
			g2.setFont(randomFont()); //设置随机生成的字体
			g2.setColor(randomColor()); //设置字符的随机颜色
			g2.drawString(s, x, h-5); //画图
		}
		this.text = sb.toString(); //随机生成的图片的内容复制给this.text
		drawLine(image); //画干扰线
		return image;
	}

	// 获取图片当中的内容
	public String getText() {
		return text;
	}

	// 保存图片到指定的输出流
	public static void output (BufferedImage image, OutputStream out)
			throws IOException {
		ImageIO.write(image, "JPEG", out);
	}
}

该工具类VerifyCode主要用于生成图形验证码相关的功能,具体如下:

  • 获取验证码内容getText()方法用于获取生成的验证码图片中的字符内容,即返回text变量的值。(该方法用于后端获取验证码内容)
  • 保存图片output()方法是一个静态方法,用于将生成的BufferedImage格式的验证码图片以 "JPEG" 格式保存到指定的输出流out中;(该方法用于将验证码的图片输出到前端页面 )

 下面演示实现过程:

(1)前端代码:

点击更换验证码功能:通过reloadCode函数实现点击验证码图片更换验证码的功能。当用户点击验证码图片时,函数会获取当前的时间戳(var time = new Date().getTime();),然后将img标签的src属性重新设置为/login/VerifyCode?id=加上获取到的时间戳(document.getElementById("imgCode").src="/login/VerifyCode?id="+time;)。这样每次点击图片时,由于src属性值发生变化(通过添加不同的时间戳来区分每次请求),图片标签就会重新调用后端/login/VerifyCode接口来获取新的验证码图片,实现了验证码的动态更新。

<div>
    <input type="text" name="Imgcode" placeholder="验证码" id="verifyCode" class="input-item"/>
    <img alt="验证码" src="/login/VerifyCode" id="imgCode" onclick="reloadCode()">
</div>
<script>
    //点击更换验证码
    function reloadCode(){
        var time = new Date().getTime();
        //鼠标每单击一次验证码图片,设置img标签的src属性,然后图片标签就会调用src指向的资源
        document.getElementById("imgCode").src="/login/VerifyCode?id="+time;
    }
</script>
(2)后端代码(验证码生成接口)

/login/VerifyCode

/**
     * 获取验证码
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/VerifyCode")
    public void VerifyCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        VerifyCode code = new VerifyCode();
        BufferedImage image = code.getImage();  //得到验证码图片
        String text = code.getText(); //得到验证码的文本

        //保存验证码的值
        HttpSession session = request.getSession(); //将验证码的值存放到session中
        session.setAttribute("verify", text);

        VerifyCode.output(image, response.getOutputStream()); //将验证码图片输出到前端页面
    }

       在上述几段代码中,实现了前端展示验证码图片、可点击更新验证码,后端生成验证码图片和文本、存储验证码文本并将图片输出到前端的完整流程,是一个常见的验证码功能实现方式。
 

完整的,附带验证码和JWT令牌验证功能的登录流程,完整代码如下:

1.前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高考帮登录</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<!--	<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>-->
<!--    <script src="../static/js/test.js" defer></script>-->
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        html {
            height: 100%;
        }
        body {
            height: 100%;
        }
        .container {
            height: 100%;
            background-image: linear-gradient(to right, rgb(54,200,180), #a6eea6);
        }
        .login-wrapper {
            background-color: #fff;
            width: 358px;
            height: 588px;
            border-radius: 15px;
            padding: 0 50px;
            position: relative;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
        }
        .header {
            font-size: 38px;
            font-weight: bold;
            text-align: center;
            line-height: 90px;
        }
        .header img{
            margin-top: 50px;
            border-radius: 15px;
            width: 200px;
        }
        .input-item {
            display: block;
            width: 100%;
            margin-bottom: 20px;
            border: 0;
            padding: 10px;
            border-bottom: 1px solid rgb(128, 125, 125);
            font-size: 15px;
            outline: none;
        }
        .input-item:placeholder {
            text-transform: uppercase;
        }
        .btn {
            text-align: center;
            padding: 10px;
            width: 100%;
            margin-top: 40px;
            background-image: linear-gradient(to right, rgb(54,200,180), #a6eea6);
            color: #fff;
        }
        .btn:hover{
        	opacity:0.7;
        }
        .msg {
            text-align: center;
            line-height: 88px;
        }
        a {
            text-decoration-line: none;
            color: #abc1ee;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="login-wrapper">
            <div class="header">
                <img src="../static/img/志愿帮01.png" alt="">
            </div>
            <form id="form1"  class="form_box">
            <div class="layui-form layui-row layui-col-space16">
            <div class="form-wrapper input-item" >
                <div class="layui-col-md6">
                    登录身份
                    <select id = "type">
                        <option value="">请选择</option>
                        <option value="111">管理员</option>
                        <option value="000">用户</option>

                    </select>
                </div>
            </div>
                <input type="text" name="username" id="username" placeholder="用户名" class="input-item">
                <input type="password" name="password" id="password" placeholder="password" class="input-item">

                <input type="text" name="Imgcode" placeholder="验证码" id="verifyCode" class="input-item"/>
                <img alt="验证码" src="/login/VerifyCode" id="imgCode" onclick="reloadCode()">

                <div class="btn" onclick="login()">Login</div>
            </div>
            </form>
            <div class="msg">
                还没有账号?
                <a href="/login/toRegister">去注册</a>
            </div>
        </div>
    </div>


<script>
    //更换验证码
    function reloadCode(){
        var time = new Date().getTime();
        //鼠标每单击一次验证码图片,设置img标签的src属性,然后图片标签就会调用src指向的资源
        document.getElementById("imgCode").src="/login/VerifyCode?id="+time;
    }

    //提交
    function login(){
        var username = $("#username").val();
        var password = $("#password").val();
        var verifyCode = $("#verifyCode").val();
        var type = $("#type").val();
        console.log(type)
        if(username === "" || username.length===0){
            alert("用户名为空");
        }else if(password === "" || password.length===0){
            alert("密码为空");
        }else if(verifyCode === "" || verifyCode.length===0){
            alert("验证码为空");
        }else{
            $.ajax({
                url: "/login/loginManage",   // 地址
                type:"post",
                data:{"username":username,"password":password,"Imgcode":verifyCode},
                success: function (value){
                    console.log(value)
                    if(value.code===0){
                        if(type==111){
                            window.location.href = '/login/toManager';
                        }else{
                            //添加token,并且跳转到system页面
                            window.location.href = '/system/';
                        }

                    }else if(value.code === 1){
                        alert(value.message);
                    }
                },
                error:function (){
                    alert("网络出错");
                }
            });
        }
    }
</script>

</body>
</html>

2.后端接口

@Controller
@RequestMapping("/login")
public class LoginController{
    @Autowired
    private UserDao userDao;

    /**
     * 1.获取验证码的接口
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/VerifyCode")
    public void VerifyCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        VerifyCode code = new VerifyCode();
        BufferedImage image = code.getImage();  //得到验证码图片
        String text = code.getText(); //得到验证码的文本

        //保存验证码的值
        HttpSession session = request.getSession(); //将验证码的值存放到session中
        session.setAttribute("verify", text);

        VerifyCode.output(image, response.getOutputStream()); //将验证码图片输出到页面
    }

    /**
     * 2.登录接口
     * @param login
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/loginManage")
    @ResponseBody
    public Result<String> login(Login login, HttpServletRequest request, HttpServletResponse response){

        HttpSession session = request.getSession();
//        System.out.println("实际的"+session.getAttribute("verify"));
//        System.out.println("我输入的:"+login.getImgcode());
        if(session.getAttribute("verify").equals(login.getImgcode())){
            //验证码正确再去做登录判断
            UserloginUser = userDao.findByUsername(login.getUsername());
            if (loginUser == null){
                return Result.error("用户不存在!");
            }

            System.out.println("我输入的密码"+login.getPassword());
            System.out.println("数据库的密码"+loginUser.getPassword());
            System.out.println(login.getPassword()==loginUser.getPassword());

            if (login.getPassword().equals(loginUser.getPassword())){
                Map<String, Object> claims = new HashMap();
                claims.put("email",loginUser.getEmail());
                claims.put("id",loginUser.getId());


                String token = JWTUtils.getToken(claims);
                //将token信息设置如cookie当中
                Cookie cookie = new Cookie("token",token);
                cookie.setPath("/");   //设置浏览器的访问路径
                cookie.setMaxAge(36000); //设置cookie的过期时间
                response.addCookie(cookie);
                return Result.success("登录成功");
            }else{
                return Result.error("密码错误!");
            }
        }else {
            return Result.error("验证码错误");
        }

    }
}

用于实现登录接口而封装的pojo类:login类

package com.yzx.springbootdemo.pojo;

public class Login {
    private Integer id;
    private String username;
    private String password;
    private String Imgcode;
    private Integer type;

    //有参和无参构造器...
    //setter和getter方法....
}


http://www.kler.cn/a/396969.html

相关文章:

  • 【机器学习】机器学习中用到的高等数学知识-1.线性代数 (Linear Algebra)
  • 大数据新视界 -- 大数据大厂之 Impala 性能优化:基于数据特征的存储格式选择(上)(19/30)
  • 使用 Python 和 OpenCV 实现摄像头人脸检测并截图
  • github和Visual Studio
  • MySQL-初识数据库
  • 前端知识点---this的用法 , this动态绑定(Javascript)
  • 网络安全审计
  • 什么是SSL VPN?其中的协议结构是怎样的?
  • 自动化测试工具Ranorex Studio(三十四)-自定义报告模板
  • 基于微信小程序的公务员考试学习平台的设计与实现,LW+源码+讲解
  • 解答疑问,为什么在本地明明拉取了镜像,但是k8s-pod依旧ImagePullBackOff
  • STM32 ADC --- 任意单通道采样
  • 社交媒体的隐私新标准:Facebook的数据保护策略
  • NDNF-RNASeq
  • Prometheus 和 Grafana 以进行服务器监控
  • 【微软报告:多模态基础模型】(1)从专家到通用助手
  • 【论文复现】智慧医疗:纹理特征VS卷积特征
  • SQL笔试题笔记(1)
  • 深度学习工具和框架详细指南:PyTorch、TensorFlow、Keras
  • 深入解析生成对抗网络(GAN)
  • Vue模块化开发的理解
  • layui 表格点击编辑感觉很好用,实现方法如下
  • ZeroSSL HTTPS SSL证书ACMESSL申请3个月证书
  • unity3d————Resources卸载资源
  • 如何构建安全可靠的 HarmonyOS 应用
  • 【软件工程】一篇入门UML建模图(类图)