jwt已经更新好几版本了,也是取代cookie的方式之一。感觉用起来还是蛮简单的,废话不多讲,直接上代码集成的核心代码。
一、jar引入
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.8.3</version> </dependency>
二、WebMvcConfigurer设置。
增加拦截器拦截器,具体:
@Override public void addInterceptors(InterceptorRegistry registry) { //接口签名认证拦截器,该签名认证比较简单,实际项目中可以使用Json Web Token或其他更好的方式替代。 //这个方法是去读取配置文件里配置的不校验token的请求,比如登录不校验 initPassUrl(); registry.addInterceptor(new HandlerInterceptorAdapter(){ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getRequestURI(); log.info("----请求的url:{}",url); //Option类型请求不校验 if(isOptionRequest(request)){ response.setStatus(200); return true; } if(isTokenCheckPassUrl(request)){ log.info("---不校验token的请求"); return true; } //以什么开头的不校验 if (!url.startsWith("/sysMobile")){ log.debug("---PC端接口暂时不校验token"); return true; } //jwt token认证处理 boolean pass = jwtTokenAuthentication(request); if (pass) { /// 反向获取用户信息 设置用户信息 //request.setAttribute("", ""); log.info("---jwt校验通过"); return true; } else { log.warn("token认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap())); Result result = new Result(); result.setCode(ResultCode.UNAUTHORIZED).setMessage("请求认证无权限或认证失败"); responseResult(response, result); return false; } } }); }
三、我的jwt的工具类(关键方法)
/** * 内部類 */ static class TokenValidationException extends RuntimeException { public TokenValidationException(String msg) { super(msg); } } /** * 手机端运营,生成token * @param loginUserDto 登录用户 * @return */ public static String mobileSysGenerateToken(SysOrgUserDto loginUserDto) { Long expSeconds = LocalHostUtil.getMobileSysLoginTokenExp(); //为空默认1小时 if (expSeconds == null){ expSeconds = 3600L; } Date iaDate = new Date(); Calendar nowTime = Calendar.getInstance(); nowTime.add(Calendar.MINUTE,1); Calendar expiresDate = Calendar.getInstance(); expiresDate.add(Calendar.SECOND,expSeconds.intValue()); Map<String,Object> map = new HashMap<>(3); map.put("alg","HS256"); map.put("typ","JWT"); String token = JWT.create().withHeader(map) .withClaim(USER_NAME,loginUserDto.getUserName()) .withClaim(ORG_CODE,loginUserDto.getOrgCode()) .withExpiresAt(expiresDate.getTime()) .withIssuedAt(iaDate) .sign(Algorithm.HMAC256(SECRET)); //jwt前面一般都会加Bearer return TOKEN_PREFIX + token; } /** * 手机运营端,验证token * @param token * @return */ public static boolean validateTokenAndAddUserIdToHeader(String token) { JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build(); DecodedJWT jwt = null; Map<String, Claim> claims = null; try { jwt = verifier.verify(token.replace(TOKEN_PREFIX, "")); claims = jwt.getClaims(); if (!CollectionUtils.isEmpty(claims)){ String tokenUserName = claims.get(USER_NAME).asString(); String tokenOrgCode = claims.get(ORG_CODE).asString(); log.info("---token用户信息--公司code:{},用户名:{}",tokenOrgCode,tokenUserName); Date expDate = jwt.getExpiresAt(); Date now = new Date(); if (now.before(expDate)){ log.info("----jwt token有效"); return true; //throw new TokenValidationException("登陆凭证已过期,请重新登陆!"); } } return false; }catch (Exception e){ if (CollectionUtils.isEmpty(claims)){ log.info("用户{}token已经过期,登录参数为空,需要重新登陆!"); }else{ log.info("用户{}token已经过期,需要重新登陆!",claims.get("name").asString()); } //throw new TokenValidationException("登陆凭证已过期,请重新登陆!"); return false; } }
上面一个是生成token,一个是验证token。我这里设计的是登录成功后,调用生成token,返回给前端,前端缓存,以后请求在head里设置token。这里的验证,会校验生成时设置的有效期。
使用就是这么简单,但是这个感觉也有弊端,因为生成的token是按照withClaim设置的顺序生成的,所以同一个用户,每次生成的token,前面几节可能是一样的,如果知道这个的人,可能可以把你的密匙试出来。加班时间到了,就写道这里吧。