天天看點

JWT 詳解

定義:JSON Web Token(縮寫 JWT)是目前最流行的跨域認證解決方案

由于HTTP協定是無狀态的,這意味着如果我們想判定一個接口是否被認證後通路,就需要借助cookie或者session會話機制進行判定,但是由于現在的系統架構大部分都不止一台伺服器,此時又要借助資料庫或者全局緩存 做存儲,這種方案顯然受限太多。

那麼我們可不可以讓認證令牌的釋出者自己去識别這個令牌是不是我曾經釋出的令牌呢(JWT核心思想),這是JWT最大的優點也是最大的缺點,優點是簡單快捷、不需要依賴任何第三方操作就能實作身份認證,缺點就是對于任何擁有使用者釋出令牌的請求都會認證通過。

 JWT 資料結構(三部分)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTkxMjAxMTgsInVzZXJuYW1lIjoibHhxIn0.YiFRESjiBc8oQuAiGo43MA1AJ2iDFJYO8AYlaor5w2w

1.Header 部分是一個 JSON 對象,描述 JWT 的中繼資料,通常是下面的樣子。

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

alg

屬性表示簽名的算法(algorithm),預設是 HMAC SHA256(寫成 HS256);

typ

屬性表示這個令牌(token)的類型(type),JWT 令牌統一寫為

JWT

2.Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的資料。JWT 規定了7個官方字段,供選用。

  • iss (issuer):簽發人
  • exp (expiration time):過期時間
  • sub (subject):主題
  • aud (audience):閱聽人
  • nbf (Not Before):生效時間
  • iat (Issued At):簽發時間
  • jti (JWT ID):編号

3.Signature 部分是對前兩部分的簽名,防止資料篡改。

首先,需要指定一個密鑰(secret)。這個密鑰隻有伺服器才知道,不能洩露給使用者。然後,使用 Header 裡面指定的簽名算法(預設是 HMAC SHA256),按照下面的公式産生簽名

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 

 算出簽名以後,把 Header、Payload、Signature 三個部分拼成一個字元串,每個部分之間用"點"(

.

)分隔,就可以傳回給使用者。

Maven依賴

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
 <version>3.5.0</version>
 </dependency>
           
**
 * @Description:
 * @Author: Lxq
 * @Date: 2019/9/6 12:25
 */
public class JwtUtil {

    /**
     * 設定token的失效時間(7天)
     */
    private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;

    /**
     * 校驗token是否正确,是否過期
     *
     * @param token    密鑰
     * @param username 使用者名
     * @param secret   密碼
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            //根據密碼生成JWT效驗器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            //效驗TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 獲得token中的資訊無需secret解密也能獲得
     *
     * @return token中包含的使用者名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成簽名,7天後過期
     *
     * @param username 使用者名
     * @param secret   使用者的密碼
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附帶username資訊
        return JWT.create()
                .withClaim("username", username)
                .withExpiresAt(date)
                .sign(algorithm);

    }
}