JWT+Interceptor实现无状态登录和鉴权 (2)

能成功解析出结果的前提是两次的盐是一样的才行

Claims map = Jwts.parser().setSigningKey("changwu") .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlvKDkuIkiLCJleHAiOjE1NjU2MTg1MjUsImlhdCI6MTU2NTYxODQ2NSwicm9sZSI6ImFkbWluIn0.GDVfLq-ehSnMCRoxVcziXkirjOg34SUUPBK5vAEHu80") .getBody(); System.out.println("用户id" + map.getId()); System.out.println("用户名" + map.getSubject()); System.out.println("token过期时间" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(map.getExpiration())); System.out.println("用户登录时间" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(map.getIssuedAt())); System.out.println("用户的角色是:"+map.get("role")); 拦截器

注意哦,使用的是SpringMvc的拦截器,而不是Servlet的过滤器

拦截器的体系架构

拦截器的继承体系

在拦截器的体系中,我们常用的是上面的来两个

HandlerInterceptor: 是顶级接口如下:

HandlerInterceptor

虽然是接口, 但是拥有jdk8的特性,是默认的方法,所以允许我们挑选它的部分方法实现而不会报错

prehandler: 请求到达控制器之间被回调,可以在这里进行设置编码,安全控制,权限校验, 一般全部返回ture,表示放行

postHandler: 控制器处理请求之后生成了ModelAndView,但是未进行渲染,提供了修改ModelAndView的机会

afterCompletion: 返回给用户ModelAndView之后执行, 用于收尾工作

第二个是HandlerInterceptorAdapter如下图

HandlerInterceptorAdapter

这个适配器方法全是空实现,同样可以满足我们的需求,但是它同时实现了AsyncHandlerInterceptor,拥有了一个新的方法,afterConcrruentHandingStarted(request,response,handler)

这个方法会在Controller方法异步执行时开始执行, 而Interceptor的postHandle方法则是需要等到Controller的异步执行完才能执行

编码实现

其实到这里改如何做已经清晰明了

用户登录,授权

授权的很简单

用户发送登录请求提交form表单

后端根据用户名密码查询用户的信息

把用户的信息封装进jwt的载荷部分

返回给前端token

用户再次请求,鉴权

后台会有很多方法需要指定权限的人才能访问, 所谓鉴定权限,其实就是把前端放在请求头中的token信息解析出来,如果解析成功了,说明用户的合法的,否则就提示前端用户没有权限

把token从请求头中解析出来的过程,其实是在大量的重复性工作,所以我们放在拦截器中实现

使用拦截器两步走

第一步,继承HandlerInterAdapter,选择重写它的方法

设计的逻辑,这个方法肯定要返回true, 因为后台的方法中肯定存在大量的不需要任何权限就能访问的方法

所以这个方法的作用就是,解析出请求头中的用户的权限信息,重新放回到request中,

这样每个需要进行权限验证的请求,就不需要再进行解析请求头,而是直接使用当前回调方法的处理结果

@Component public class RequestInterceptor extends HandlerInterceptorAdapter { @Autowired JwtUtil jwtUtil; // 在请求进入处理器之前回调这个方法 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取请求头 String header = request.getHeader("Authorization"); // 请求头不为空进行解析 if (StringUtils.isNotBlank(header)) { // 按照我们和前端约定的格式进行处理 if (header.startsWith("Bearer ")){ // 得到令牌 String token = header.substring(7); // 验证令牌 try{ // 令牌的解析这里一定的try起来,因为它解析错误的令牌时,会报错 // 当然你也可以在自定义的jwtUtil中把异常 try起来,这里就不用写了 Claims claims = jwtUtil.parseJWT(token); String roles =(String) claims.get("roles"); System.err.println("roles=="+roles); if (roles!=null&&"admin".equals(roles)){ request.setAttribute("role_admin",token); } if (roles!=null&&"user".equals(roles)){ request.setAttribute("role_user",token); } }catch (Exception e){ throw new RuntimeException("令牌不存在"); } } } return true; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyyjz.html