目录
前言
一、初步认识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()方法进行生成
@Testpublic 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//验证tokenpublic 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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {/*通过HttpServletRequest的实例request,可以访问到所有的前端请求;1.再调用request中的getHeader()方法访问前端请求中的请求头2.请求头中"Authorization"关键字对应的是token字符串*///获取前端请求中的tokenString token = request.getHeader("Authorization");//验证tokentry {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*/@Overridepublic 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 {@Autowiredprivate LoginInterceptor loginInterceptor;/*** @param registry*/@Overridepublic 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";//接受用户信息,返回生成的tokenpublic 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")@ResponseBodypublic 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.textdrawLine(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{@Autowiredprivate 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")@ResponseBodypublic 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方法....
}