springboot集成json web token

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章