基於JWT(JSON Web Token)的token身份驗證

相逢即是,路過點個^.^php


源碼:https://github.com/yulc-coding/java-note/tree/master/jwt css

介紹

JWT是一種用於通訊雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規範,常常用在跨域身份驗證。由於存在數字簽名,所以能夠起到防串改的做用前端

傳統session模式

相對於傳統的session認證,一般將session保存在服務端,須要服務器去維護。而且在服務器集羣或請求服務跨域的狀況下,須要共享session,使每臺服務器都能讀取session,好比將session持久化,增長了開銷。java

jwt token模式

用戶登陸後服務器將相關數據生成一個token返回客戶端
客戶端每次發起請求帶上token
服務器獲取token後校驗token驗證合法性git

格式

  • Header 頭信息
{
  "alg""Algorithm  加密方法:HS256",
  "cty""Content Type ",
  "typ""Type" ,
  "kid""Key Id"
 }
複製代碼
  • Payload 載體信息:數據包放在這裏
{
  "iss""Issuer JWT的簽發者",
  "aud""Audience 接收JWT的一方",
  "sub""Subject JWT的主題",
  "exp""Expiration Time JWT的過時時間",
  "nbf""Not Before 在xxx之間,該JWT都是可用的",
  "iat""Issued At 該JWT簽發的時間",
  "jti""JWT ID JWT的惟一身份標識",
  "xxx""自定義屬性"
}
複製代碼
  • Signature 簽名信息 = 加密算法(header + "." + payload, 密鑰)github

  • TOKENweb

base64(Header).base64(Payload).Signature
複製代碼

代碼

pom

    <!-- JWT 支持-->
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.8.3</version>
    </dependency>

    <!-- 很好用的一個工具類包 這裏用來處理json和AES加密-->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.0.3</version>
    </dependency>
複製代碼

建立token

能夠傳入公有聲明的字段,也能夠傳入自定義的字段算法

   /**
     * 建立token
     *
     * @param json 須要放入token的參數,多個參數能夠封裝成json或者map
     * @return token
     */

    public static String createToken(JSONObject json) {
        try {
            // 加密方式
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            return JWT.create()
                    .withSubject(json.toString())
                    .withIssuer("ylc")
                    // 設置過時時間爲1分鐘後
                    .withExpiresAt(DateUtil.offsetMinute(new Date(), 1))
                    .withClaim("customString""自定義參數")
                    .withArrayClaim("customArray"new Integer[]{123})
                    .sign(algorithm);
        } catch (JWTCreationException exception) {
            //Invalid Signing configuration / Couldn't convert Claims.
            System.out.println(exception.getMessage());
            return null;
        }
    }
複製代碼

token校驗

包含:
格式校驗:header.payload.signature
加密方式校驗: Header中的alg值
簽名信息Signature校驗,防止數據被篡改
載體Payload 中公有聲明字段校驗,如iss,jti,exp過時時間的校驗json

    /**
     * 校驗token 合法性
     *
     * @param token to verify.
     */

    public static boolean verifyToke(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    // 驗證簽發人是否相同
                    .withIssuer("ylc")
                    .build();
            /*
             * 校驗:
             * 格式校驗:header.payload.signature
             * 加密方式校驗 Header中的alg
             * 簽名信息校驗,防串改
             * 載體Payload 中公有聲明字段校驗
             */

            verifier.verify(token);
            return true;
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            System.out.println(exception.getMessage());
            return false;
        }
    }
複製代碼

解析token

能夠經過jwt.getClaims() 獲取全部聲明字段
也能夠經過 jwt.getClaim(name) 獲取指定名稱的聲明字段跨域

/**
 * 解析token
 *
 * @param token to decode.
 */

public static void decodeToken(String token{
    try {
        DecodedJWT jwt = JWT.decode(token);
        Map<String, Claim> claims = jwt.getClaims();
        Claim customStringClaim = claims.get("customString");
        Claim customArrayClaim = claims.get("customArray");

        String issuer = jwt.getIssuer();
        String subject = jwt.getSubject();

        System.out.println(customStringClaim.asString());
        System.out.println(Arrays.toString(customArrayClaim.asArray(Integer.class)));
        System.out.println(issuer);
        System.out.println(JSONUtil.parseObj(subject));

    } catch (JWTDecodeException exception) {
        //Invalid token
        System.out.println(exception.getMessage());
    }
}
複製代碼

缺點

  • 默認生成的token不加密,別人能夠解析token獲取到其中的數據,若是要傳遞敏感信息,能夠先將信息加密後再放入token,或者將生成的token進行加密
  • 每次延長token有效期,會重新生成一個token,須要前端替換原有的token
  • 因爲服務器不保存 session狀態,所以沒法在使用過程當中廢止某個token,或者更改 token的權限。也就是說,一旦JWT簽發了,在到期以前就會始終有效,須要在服務端設置相應的業務邏輯去處理。
相關文章
相關標籤/搜索