导言 :该文最终本人实现目的为通过JWT来生成token作为用户登录或调用api等身份验证凭证,同时简单的引入了Redis作为缓存来存放Token。用最简洁的方法给第一次接触Token的朋友们快速入门并且实际运用到项目中。不纠结于理论,只聚焦于实战,如果有希望了解更多理论的朋友,可以在看本文的过程中查询其他理论性文章。
这几天毕设项目正准备开始搞,想到之前的项目登录没有做token密码只是md5加密,再加上实习导师的建议,我就开始搞了JWT+Redis,查了诸多参考文献资料等,花了三天时间基本完成了这个功能。
复制代码 io.jsonwebtoken jjwt 0.9.1
Token分为三个部分,头,荷载,和签名,我们需要对这几个部分分别设置,第一个方法为创建一个JsonWebToken
第二个工具类为检查 token
是否正常,值得注意的是,除了解析后的姓名身份等等,如果时间异常(已经超过有效期)也将被 catch
异常,所以直接写在 try-catch
中即可
//JsonWebTokenUtil public class JsonWebToken { private static longtime= 1000*60*60*24; private static Stringsignature= "9991morF0GgnahZ"; public static String createToken(String role,String name){ JwtBuilder jwtBuilder = Jwts.builder(); String jwToken = jwtBuilder //链式编程 添加头 .setHeaderParam("typ","JWT") .setHeaderParam("alg","HS256") //payload 载荷 .claim("name",name) .claim("role",role) //主题 .setSubject("admin") //有效期 .setExpiration(new Date(System.currentTimeMillis()+time)) .setId(UUID.randomUUID().toString()) //signature签名 .signWith(SignatureAlgorithm.HS256,signature) //拼接前面三个 .compact(); return jwToken; } public static boolean checkToken(String token){ if (Objects.equals(token, "") || token == null){ return false; } try { //解析后拿到存有token信息的集合 JwsclaimsJws1 = Jwts.parser().setSigningKey(signature).parseClaimsJws(token); } catch (Exception e) { System.out.println("【Error】token解密异常"); e.printStackTrace(); return false; } return true; // Claims claims = claimsJws1.getBody(); // System.out.println(claims.get("name")); // System.out.println(claims.get("role")); // System.out.println(claims.getId()); } } 复制代码
只展示与Token相关核心代码
adminLogin
为登录VO内有phone password token三个字段,最后返回时将password清空保证安全(并非唯一方式也并非最佳方式此返回仅供参考)
getOne
为本人写的获取用户信息的函数,并非本文重点内容,在此声明不做阐述。
String name = getOne(queryWrapper).getAdminName(); //下面为核心代码 //获取Token adminLogin.setToken(JsonWebToken.createToken("admin",name)); //将用户token写入Redis缓存 以token为key与value前端不用多传值,后两个参数为过期时间 stringRedisTemplate.opsForValue().set(adminLogin.getToken(),adminLogin.getToken(),1000*60*60*24*7, TimeUnit.SECONDS); //上面为核心代码 adminLogin.setPassword(""); return JsonResultUtils.successMsg("登录成功",adminLogin); 复制代码
完成到这一步之后,恭喜你已经完成了基础的token配置(可以配合解析token直接用了)但是,一般来说我们用户使用过程中会让有些功能需要token,有些功能不需要token,那具体那些需要哪些不需要呢?我们需要在后台做一个URL的区分,这个时候就需要用到 拦截器
第一步需要先写好拦截的控制方法
在下面代码中已有对应的详细注释,只对个别点做单独说明
Authorization
为前端设置的在请求头中放置的token值,后续会有说明前端如何设置
@Component public class TokenHandler implements HandlerInterceptor { @Autowired private StringRedisTemplate stringRedisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 注意:放行浏览器的预检请求 System.out.println("进入预检"); if (request.getMethod().equals("OPTIONS")) { return true; } // 获取请求头中携带的token值 String token = request.getHeader("Authorization"); // token验证 //查看token是否为空 查看token是否合法 if(JsonWebToken.checkToken(token)) { //查看Redis中有无token String value = stringRedisTemplate.opsForValue().get(token); if (Objects.equals(value, token)) { System.out.println("【success】token与redis中的匹配成功"); return true; } } System.out.println("【error】 token与redis中的匹配失败"); // throw new Exception("【error】 token与redis中的匹配失败"); // 验证失败,拦截请求 return false; } } 复制代码
第二步我们需要去写好拦截的配置
第一个方法为拦截器方法,在注释中已经讲的很明白了,如有多个排除拦截URL,用逗号分隔,或者写在List中
第二个方法为跨域,反正你先这样配上,控制层用注解去跨域,因为根据查阅的部分资料文章说这个跨域可能会影响token,我没碰到过不清楚,反正先配上hh
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private TokenHandler tokenHandler; @Override public void addInterceptors(InterceptorRegistry registry) { //添加tokenHandler拦截器 全部拦截 排除"/admin/login" registry.addInterceptor(tokenHandler).addPathPatterns("/**").excludePathPatterns("/admin/login"); } //跨域配置 @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许跨域请求的地址 .allowedOriginPatterns("*") // 允许跨域请求的域名 .allowedMethods("GET", "POST", "PUT", "DELETE", "PATH") // 允许请求的方式 .allowCredentials(true) // 是否允许证书(cookies) .maxAge(3000); // 跨域允许时间 } } 复制代码
至此为止你的token就已经大功告成了!
配置axios的request方法中拦截request方法
注意:如果你出错了,请检查你是否拿到token时把其存入了localStorage!
Request.interceptors.request.use(config => { config.headers['Content-Type'] = 'application/json;charset=utf-8'; // 在浏览器的 Session Storage 中拿到 token 值 config.headers.Authorization =window.localStorage.getItem("token"); return config; }) 复制代码
复制代码 org.springframework.boot spring-boot-starter-data-redis
如果出错!请想一想你装Redis没,装了开没,开了ping没,ping了pong没。
如果一切正常但是依旧报错,请移步搜索,因为我没踩过坑…