JSON WEB TOKE入門原理與實際案例測試

1.什麼是JWT?

 JWT全稱JSON Web Token。是爲了在網絡應用環境鍵傳遞聲明而執行的一種基於JSON的開放標準。

2.JWT的使用場景?

  授權:一旦用戶登錄,每個後續請求將包括JWT,允許用戶訪問該令牌允許的路由,服務和資源。單點登錄是一種在廣泛使用JWT的功能,因爲它的開銷很小,並且能夠在不同的域中輕鬆使用。

  信息交換:JSON Web令牌是在各方之間安全傳輸信息的好方法。因爲JWT可以簽名 - 例如,使用公鑰/私鑰對 - 您可以確定發件人是他們所說的人。此外,由於使用標頭和有效負載計算簽名,您還可以驗證內容是否未被篡改。

3.JWT的結構組成?

  由三部分組成,用(.)進行分隔,他們是

  • 頭部(header)
  • 有效載荷(payload)
  • 簽名(signature)

  因此,JWT通常如下表示

  xxxxxx.yyyyy.zzzzz

  頭部:

  JWT頭部分是一個描述JWT元數據的JSON對象,通常如下所示

  

       在上面的代碼中,alg屬性表示簽名使用的算法,默認爲HMAC SHA256(寫爲HS256);typ屬性表示令牌的類型,JWT令牌統一寫爲JWT。然後,這個json被編碼稱Base64Url,形成JWT的第一部分。

  有效載荷:

  有效載荷是JWT的主體內容部分,也是一個JSON對象,包含需要傳遞的數據。JWT指定七個默認字段供選擇。

  iss:發行人

  exp:到期時間

  sup:主題

  aud:用戶

  nbf:在此之前不可用

  iat:發行時間

  jti:JWT ID用於標識該JWT

  除以上默認字段外,我們還可以自定義私有字段,如下例:

  

  請注意,默認情況下JWT是未加密的,任何人都可以解讀其內容,因此不要構建隱私信息字段,存放保密信息,以防止信息泄露。

  JSON對象也使用Base64 URL算法轉換爲字符串保存,形成JWT第二部分。

  簽名:

  簽名是對上面兩部分數據簽名,通過指定的算法生成哈希,以確保數據不會被篡改。

  首先,需要制定一個密鑰(secret)。該密鑰僅僅爲保存在服務器中,並且不能向用戶公開。然後,使用頭部中指定的簽名算法(默認情況下爲HMACSHA256)根據以下公式生成簽名。

  

  在計算出簽名後,將JWT頭部,有效載荷和簽名的三個部分組合成一個字符串,每個部分用"."分隔,就構成整個JWT對象,返回給用戶。

4.JWT的用法?

  JWT的原理是,服務器認證以後,生成一個JSON對象,發回給用戶,如下面格式

  {
    "姓名": "張三",
    "角色": "管理員",
    "到期時間": "2018年7月1日0點0分"
  }

  以後用戶與服務端通信的時候,都要返回這個JSON對象。服務器完全只靠這個對象認定用戶身份。爲了防止用戶篡改數據,服務器在生成這個對象的時候,會加上簽名。

  客戶端收到服務器返回的JWT,可以存儲到Cookie裏面,也可以存儲到localStorage。

  此後,客戶端每次與服務器通信,都要帶上這個JWT。你可以把它放在cookie裏面自動發送,但是這樣就不能實現跨域。所以更好的做法是放在HTTP請求的頭信息Authorization字段裏面

  另一種做法是,跨域的時候,JWT就放在POST請求的數據裏面。

5.JWT特點?

  (1)JWT默認是不加密的,但也是可以加密的。生成原始Token以後,可以用密鑰在加密一次。

  (2)JWT不加密的情況下,不能將祕密數據寫入JWT。

  (3)JWT不僅可以用於認證,也可以死用於交換信息。有效使用JWT,可以降低服務器的查詢數據庫的次數。

  (4)JWT最大的缺點是,用於服務器不保存sessi000on狀態,因此無法在使用過程中廢止某個token,或者更改token的權限,也就是說,一旦JWT簽發了,在到期之前就會始終有效,除非服務器部署額外的邏輯。

  (5)JWT本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限。爲了減少盜用,JWT的有效期限應該設置的比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。

  (6)爲了較少盜用,JWT不應該使用HTTP協議明碼傳輸,要使用HTTPS協議傳輸。

 7.JWT的入門案例(Java方式)

   創建一個項目,先引入依賴。

 <dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.0</version>
 </dependency>
 <dependency>
     <groupId>com.auth0</groupId>
     <artifactId>java-jwt</artifactId>
     <version>3.2.0</version>
 </dependency>
public class TokenUtil {
    private static final String APP_KEY = "why_key"; //進行數字簽名的私鑰,一定要保管好,不能和我一樣寫到博客中。。。。。

    private TokenUtil(){

    }
    /**
     * 一個JWT實際上就是一個字符串,它由三部分組成,頭部(Header)、載荷(Payload)與簽名(Signature)
     * @param id 當前用戶ID
     * @param issuer 該JWT的簽發者,是否使用是可選的
     * @param subject 該JWT所面向的用戶,是否使用是可選的
     * @param ttlMillis 什麼時候過期,這裏是一個Unix時間戳,是否使用是可選的
     * @param audience 接收該JWT的一方,是否使用是可選的
     * @return
     */
    public static String createJWT(String id,String issuer,String subject,long ttlMillis, String audience){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(APP_KEY);

        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        JwtBuilder jwtBuilder = Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .setIssuer(issuer)
                .setAudience(audience)
                .claim("name","自定義字段")
                .signWith(signatureAlgorithm,signingKey);
        //設置Token的過期時間
        if(ttlMillis >=0){
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            jwtBuilder.setExpiration(exp);
        }

        return jwtBuilder.compact();

    }

    //私鑰解密token信息
    public static Claims getClaims(String jwt) {
        return Jwts.parser()
                .setSigningKey(DatatypeConverter.parseBase64Binary(APP_KEY))
                .parseClaimsJws(jwt).getBody();
    }

}

編寫一個Test類來測試一下

public class JsonWebTokenTest {
    @Test
    public void jsonTest(){
        String userId = "xyzjidgdgd";
        String issuer = "https://baidu.com";
        String subject = "技術部";
        long ttlMillis = 1000 * 60;
        String audience = "技術部測試";
        String token = TokenUtil.createJWT(userId,issuer,subject,ttlMillis,audience);
        //打印出token信息
        System.out.println(token);


//        解密token信息
        Claims claims = TokenUtil.getClaims(token);
        System.out.println("---------------------------解密的token信息----------------------------------");
        System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());
        //自定義字段的獲取方式有所不同
        System.out.println("Expiration: " + claims.get("name", String.class));
    }
}

 

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