1. 程式人生 > 其它 >JWT(JSON Web Token)認證小結

JWT(JSON Web Token)認證小結

技術標籤:java後端# SpringBootjwtspring bootjava

jwt(JSON Web Token)

在這裡插入圖片描述

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC

algorithm) or a public/private key pair using RSA or ECDSA.

Jwt簡介

  • 傳統認證通過session,但是前後端分離和分散式專案無法使用,

  • jwt向認證成功的使用者返回一個token,以後使用者每次請求都攜帶該token來實現認證

  • 請求認證的token存放在客戶端localStorage中,請求時資料攜帶在header中,退出登入在loacalStorage中刪除該token即可

JWT結構

組成

jwt令牌由三部分組成

  1. 頭部(Header)
  2. 有效荷載(payload)
  3. 簽名(signature)

因此,JWT通常是xxxx.yyy.zzz

的形式

頭部(Header)

明文示例

{
    "alg":"HS256",
    "typ":"JWT"
}

alg:加密演算法

typ :型別

header部分會使用base64編碼,注意,base64並不是加密的過程,可以解碼

Payload

{
    "sub":"123465",
    "name":"zhansan",
    "admin":true
}

資料負載部分也會使用base64進行編碼,payLoad不要存放使用者敏感資訊

簽名(signature)

簽名使用編碼後的header和payload,以及一個金鑰,然後使用header中指定的簽名演算法進行簽名,簽名的作用是保證JWT沒有被篡改過

使用

pom依賴

 <dependency>
     <groupId>com.auth0</groupId>
     <artifactId>java-jwt</artifactId>
     <version>3.4.0</version>
</dependency>

生成token

//加密口令
String SECRET = "!Q$#&^&SCMd12";
Algorithm algorithm =  Algorithm.HMAC256(SECRET);

//設施過期時間為10min
Calendar expireTime =Calendar.getInstance();
expireTime.add(Calendar.MINUTE,10);
Map<String,Object> map = new HashMap<>();
map.put("alg","HS256");
map.put("typ","JWT");

String tokenStr = JWT.create()
    //header可以不用設定,一般用預設的就行
    .withHeader(map)
    .withClaim("uid", UUID.randomUUID().toString())
    .withClaim("name", "console")
    .withExpiresAt(expireTime.getTime())
    .sign(algorithm);
}

解析token

//加密口令
String SECRET = "!Q$#&^&SCMd12";
Algorithm algorithm =  Algorithm.HMAC256(SECRET);

JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT verify = verifier.verify(token);

System.out.println(verify.getHeader());
System.out.println(verify.getPayload());
System.out.println(verify.getSignature());

System.out.println(verify.getClaim("uid").asString());

一個示例util類

public class JwtUtil {
    private final static String  secretKey = "[email protected]#*&^&%^&BHv*h)dk782GYh";
    /**
     * 加密演算法
     */
    private static Algorithm algorithm =  Algorithm.HMAC256(secretKey);

    /**
     * 過期時間單位
     */
    private static int expiresUnit = Calendar.DAY_OF_YEAR;
    /**
     * 過期時間值
     */
    private static int expireAmount = 7;


    /**
     * 生成token
     * @param param payload中攜帶的資料對
     * @return
     */
    public static String generateToken(Map<String,String> param){
        JWTCreator.Builder builder = JWT.create();
        param.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        Calendar instance = Calendar.getInstance();
        instance.add(expiresUnit,expireAmount);
        builder.withExpiresAt(instance.getTime());
        String token = builder.sign(algorithm);
        return token;
    }

    /**
     * 生成token,payload中只有一組資訊
     * @param key 攜帶資料的key
     * @param value 攜帶資料的值
     * @return
     */
    public static String generateToken(String key, String value){
        JWTCreator.Builder builder = JWT.create();

        Calendar instance = Calendar.getInstance();
        instance.add(expiresUnit,expireAmount);
        builder.withClaim(key,value);
        builder.withExpiresAt(instance.getTime());
        String token = builder.sign(algorithm);
        return token;
    }


    /**
     * 驗證token,驗證失敗會丟擲異常
     * @param token 需要驗證的token
     * @return 解碼後的token,可以獲取寫入的值
     */
    public static DecodedJWT verifyToken(String token){
        DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
        return  decodedJWT;
    }
}

攔截器

配置了jwt後,使用攔截器對使用者的token進行驗證

public class JwtInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String,Object> map = new HashMap<>();
        String token = request.getHeader("token");
        try{
            DecodedJWT decodedJWT = JwtUtil.verifyToken(token);
            //放行
            return true;
        }catch (SignatureVerificationException e){
            map.put("msg","無效簽名");
        }catch (TokenExpiredException e){
            map.put("msg","token過期");
        }catch (AlgorithmMismatchException e){
            map.put("msg","token演算法不一致");
        }catch (Exception e){
            map.put("msg","無效token");
        }

        map.put("status",false);

        //返回json資料
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(json);
        return false;
    }
}

攔截配置

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/");
    }
}