天天看點

JWT(JSON Web Token)+統一token處理

 JWT

        JSON Web Token簡稱JWT,是用于對應程式上的使用者進行身份驗證的标記。也就是說,使用JWTS的應用程式不再需要儲存有關其使用者的cookie和session資料。此特性便于可伸縮性,同時保證應用程式的安全。

格式:

JWT就是一個字元串,經過加密處理和校驗處理的字元串,形式為:A.B.C

  • A由JWT頭部資訊header加密得到
  • B由JWT用到的身份驗證資訊json資料加密得到
  • C由A和B加密得到,是校驗部分
JWT(JSON Web Token)+統一token處理

認證流程:

JWT(JSON Web Token)+統一token處理

JWT認證流程

Springboot整合JWT:

依賴:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
           

JWT工具類:

工具類實作token的生成、從token中擷取claims資訊、驗證token的有效性三個功能。

public class JwtUtils{
    private static final int TOKEN_TIME_OUT = 3600; //token的有效期為1小時
    private static final String TOKEN_SECRET = "itcast"; //加密key、
    
    /**
     * 生成Token
     *
     * @param params
     * @return
     */
     public static String getToken(Map params){
         long currentTime = System.currentTimeMillis();
         return Jwts.builder()
                 .signWith(SignatureAlgorithm.HS512, TOKEN_SECRET)  //加密方式
                 .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //過期時間戳
                 .addClaims(params)
                 .compact();    
     }
    /**
     * 擷取token中的claims資訊
     *
     * @param token
     * @return
     */
     public static Claims getClaims(String token){
         return Jwts.parser()
                 .setSigningKey(TOKEN_SECRET)
                 .parseClaimsJws(token)
                 .getBody();     
     }
    /**
     * Token是否有效 true--有效 false--無效
     * @param token
     * @return
     */
     public static boolean verifyToken(String token){
         if(StringUtils.isEmpty(token)){
             return false;         
         }              
         try{
             Claims claims = Jwts.parser()
                     .setSigningKey(TOKEN_SECRET)
                     .parseClaims(token)
                     .getBody();                                  
         }catch(Exception e){
             return false;                      
         }
         return true;
     }
}
           

統一token處理:

基于ThreadLocal+攔截器的形式統一處理

JWT(JSON Web Token)+統一token處理

ThreadLocal+攔截器處理token

  ThreadLocal:

  • 線程内部的存儲類,賦予了線程存儲資料的能力;
  • 線程内調用的方法都可以從ThreadLocal中擷取同一個對象
  • 多線程中ThreadLocal資料互相隔離

    定義ThreadLocal工具類,調用set方法将資料存入ThreadLocal中。

/**
 * @Author zzw2000
 * @Date 2022年04月15日 10:47
 * @Description 向ThreadLocal中存入使用者資料
 */
public class UserHodler{
    private static ThreadLocal<User> tl = new ThreadLocal<>();

    //将使用者對象存入ThreadLocal對象中
    public static void set(User user) {
        tl.set(user);
    }

    //從目前線程擷取User對象
    public static User getUser() {
        return tl.get();
    }

    //從目前線程中擷取User對象的id
    public static Long getId(){
        return tl.get().getId();    
    }

    //從目前線程中擷取使用者手機号
    public static String getMobile(){
        return tl.get().getMobile();
    }

    //清空線程中記錄的使用者資訊
    public static void remove(){
        tl.remove();
    }
}
           

  攔截器:

  • 是一種動态攔截方法調用的機制;
  • 類似于Servlet開發中的過濾器Filter,用于對處理器進行前置處理和後置處理。
JWT(JSON Web Token)+統一token處理

攔截器工作原理

        在前置攔截方法preHandle中解析token并驗證有效性,如果失效傳回狀态碼401(未經授權) ,若有效,解析User,并存入ThreadLocal。

/**
 * @Author zzw2000
 * @Date 2022年04月15日 10:27
 * @Description 登入攔截
 */
public class TokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        //擷取請求頭
        String token = request.getHeader("Authorization");
        //判斷token是否失效,
        if(!JwtUtils.verifyToken(token)){
            //token失效,設定狀态碼為401
            response.setStatus(401);
            //攔截 
            return false;       
        }
        //token有效,解析token,擷取使用者id和手機号,構造使用者對象,存入ThreadLocal中
        Claims claims = JwtUtils.getClaims(token);
        Integer id = (Integer) claims.get("id");
        String mobile = (String) claims.get("mobile"); 
    
        User user = new User();
        user.setId(Long.valueOf(id)); //字段id為Long類型的
        user.setMobile(mobile);
        //将user對象儲存到ThreadLocal
        UserHolder.set(user);
        //放行
        retrun true;
    }
}
           

注冊攔截器:

将上面的攔截器注冊到springboot中,交給springboot管理。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptor(InterceptorRegistry registry) {
        String[] url = {"/user/login", "/login/loginVerification"};
        registry.addInterceptor(new TokenInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(url);
    }
}