SpringBoot中过滤器Filter+JWT令牌实现登录验证
登录校验-Filter
分析
过滤器Filter的快速入门以及使用细节我们已经介绍完了,接下来最后一步,我们需要使用过滤器Filter来完成案例当中的登录校验功能。
我们先来回顾下前面分析过的登录校验的基本流程:
要进入到后台管理系统,我们必须先完成登录操作,此时就需要访问登录接口login。
登录成功之后,我们会在服务端生成一个JWT令牌,并且把JWT令牌返回给前端,前端会将JWT令牌存储下来。
在后续的每一次请求当中,都会将JWT令牌携带到服务端,请求到达服务端之后,要想去访问对应的业务功能,此时我们必须先要校验令牌的有效性。
对于校验令牌的这一块操作,我们使用登录校验的过滤器,在过滤器当中来校验令牌的有效性。如果令牌是无效的,就响应一个错误的信息,也不会再去放行访问对应的资源了。如果令牌存在,并且它是有效的,此时就会放行去访问对应的web资源,执行相应的业务操作。
大概清楚了在Filter过滤器的实现步骤了,那在正式开发登录校验过滤器之前,我们思考两个问题:
所有的请求,拦截到了之后,都需要校验令牌吗?
- 答案:登录请求例外
拦截到请求后,什么情况下才可以放行,执行业务操作?
- 答案:有令牌,且令牌校验通过(合法);否则都返回未登录错误结果
具体流程
我们要完成登录校验,主要是利用Filter过滤器实现,而Filter过滤器的流程步骤:
基于上面的业务流程,我们分析出具体的操作步骤:
- 获取请求url
- 判断请求url中是否包含login,如果包含,说明是登录操作,放行
- 获取请求头中的令牌(token)
- 判断令牌是否存在,如果不存在,返回错误结果(未登录)
- 解析token,如果解析失败,返回错误结果(未登录)
- 放行
代码实现
分析清楚了以上的问题后,我们就参照接口文档来开发登录功能了,登录接口描述如下:
请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
---|---|---|---|
username | string | 必须 | 用户名 |
password | string | 必须 | 密码 |
请求数据样例:
{ "username": "jinyong", "password": "123456" }
响应数据
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
---|---|---|---|---|---|
code | number | 必须 | 响应码, 1 成功 ; 0 失败 | ||
msg | string | 非必须 | 提示信息 | ||
data | string | 必须 | 返回的数据 , jwt令牌 |
响应数据样例:
{ "code": 1, "msg": "success", "data": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo" }
备注说明
用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为 token ,值为 登录时下发的JWT令牌。
如果检测到用户未登录,则会返回如下固定错误信息:
{ "code": 0, "msg": "NOT_LOGIN", "data": null }
登录校验过滤器:LoginCheckFilter
@Slf4j @WebFilter(urlPatterns = "/*") //拦截所有请求 public class LoginCheckFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { //前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法) HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; //1.获取请求url String url = request.getRequestURL().toString(); log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行 if(url.contains("/login")){ chain.doFilter(request, response);//放行请求 return;//结束当前方法的执行 } //3.获取请求头中的令牌(token) String token = request.getHeader("token"); log.info("从请求头中获取的令牌:{}",token); //4.判断令牌是否存在,如果不存在,返回错误结果(未登录) if(!StringUtils.hasLength(token)){ log.info("Token不存在"); Result responseResult = Result.error("NOT_LOGIN"); //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类) String json = JSONObject.toJSONString(responseResult); response.setContentType("application/json;charset=utf-8"); //响应 response.getWriter().write(json); return; } //5.解析token,如果解析失败,返回错误结果(未登录) try { JwtUtils.parseJWT(token); }catch (Exception e){ log.info("令牌解析失败!"); Result responseResult = Result.error("NOT_LOGIN"); //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类) String json = JSONObject.toJSONString(responseResult); response.setContentType("application/json;charset=utf-8"); //响应 response.getWriter().write(json); return; } //6.放行 chain.doFilter(request, response); } }
JWT导入的maven依赖
<!--JWT令牌--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
JWT的工具类
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import java.util.Map; public class JwtUtils { private static String signKey = "shisan"; private static Long expire = 43200000L; /** * 生成JWT令牌 * @param claims JWT第二部分负载 payload 中存储的内容 * @return */ public static String generateJwt(Map<String, Object> claims){ String jwt = Jwts.builder() .addClaims(claims) .signWith(SignatureAlgorithm.HS256, signKey) .setExpiration(new Date(System.currentTimeMillis() + expire)) .compact(); return jwt; } /** * 解析JWT令牌 * @param jwt JWT令牌 * @return JWT第二部分负载 payload 中存储的内容 */ public static Claims parseJWT(String jwt){ Claims claims = Jwts.parser() .setSigningKey(signKey) .parseClaimsJws(jwt) .getBody(); return claims; } }
在上述过滤器的功能实现中,我们使用到了一个第三方json处理的工具包fastjson。我们要想使用,需要引入如下依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency>
登录校验的过滤器我们编写完成了,接下来我们就可以重新启动服务来做一个测试:
测试前先把之前所编写的测试使用的过滤器,暂时注释掉。直接将@WebFilter注解给注释掉即可。
测试1:未登录是否可以访问部门管理页面
首先关闭浏览器,重新打开浏览器,在地址栏中输入:http://localhost:9528/#/system/dept
由于用户没有登录,登录校验过滤器返回错误信息,前端页面根据返回的错误信息结果,自动跳转到登录页面了
测试2:先进行登录操作,再访问部门管理页面
登录校验成功之后,可以正常访问相关业务操作页面
总结: 这个过滤器检查请求的URL是否包含 “login”。如果包含,则直接允许请求继续。如果不包含 “login”,则检查JWT令牌的存在和有效性。如果令牌不存在或无效,返回一个JSON格式的 “NOT_LOGIN” 错误响应。如果令牌存在并且有效,则允许请求继续。
到此这篇关于SpringBoot-过滤器Filter+JWT令牌实现登录验证的文章就介绍到这了,更多相关SpringBoot 登录验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
解读HttpServletRequestWrapper处理request数据流多次读取问题
在Java Web开发中,获取HTTP请求参数是常见需求,本文详细讨论了通过POST方式获取参数的两种主要方法:使用request.getParameter()适用于application/x-www-form-urlencoded和multipart/form-data内容类型;而对于application/json类型的数据2024-10-10SpringBoot 监控管理模块actuator没有权限的问题解决方法
这篇文章主要介绍了SpringBoot 监控管理模块actuator没有权限的问题解决方法,需要的朋友可以参考下2017-12-12
最新评论