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,前面幾節可能是一樣的,如果知道這個的人,可能可以把你的密匙試出來。加班時間到了,就寫道這裏吧。