JWT令牌簡介及demo


一、訪問令牌的類型

二、JWT令牌

1、什么是JWT令牌

​ JWT是JSON Web Token的縮寫,即JSON Web令牌,是一種自包含令牌。

JWT的使用場景:

  • 一種情況是webapi,類似之前的阿里雲播放憑證的功能

  • 另一種情況是多web服務器下實現無狀態分布式身份驗證

    JWT官網有一張圖描述了JWT的認證過程:

JWT的作用:
JWT 最重要的作用就是對 token信息的防偽作用

JWT的原理:

​ 一個JWT由三個部分組成:JWT頭、有效載荷、簽名哈希,最后由這三者組合進行base64編碼得到JWT

2、JWT令牌的組成

典型的,一個JWT看起來如下圖:https://jwt.io/

該對象為一個很長的字符串,字符之間通過"."分隔符分為三個子串。

每一個子串表示了一個功能塊,總共有以下三個部分:JWT頭、有效載荷和簽名

JWT頭

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

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

​ 在上面的代碼中,alg屬性表示簽名使用的算法,默認為HMAC SHA256(寫為HS256);typ屬性表示令牌的類型,JWT令牌統一寫為JWT。最后,使用Base64URL算法將上述JSON對象轉換為字符串保存。

有效載荷

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

iss: jwt簽發者
sub: 主題
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大於簽發時間
nbf: 定義在什么時間之前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

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

{
  "name": "Helen",
  "admin": true,
  "avatar": "helen.jpg"
}

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

JSON對象也使用Base64 URL算法轉換為字符串保存。

簽名哈希

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

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

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

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

Base64URL算法

如前所述,JWT頭和有效載荷序列化的算法都用到了Base64URL。該算法和常見Base64算法類似,稍有差別。

作為令牌的JWT可以放在URL中(例如api.example/?token=xxx)。 Base64中用的三個字符是"+","/"和"=",由於在URL中有特殊含義,因此Base64URL中對他們做了替換:"="去掉,"+"用"-"替換,"/"用"_"替換,這就是Base64URL算法。

注意:base64編碼,並不是加密,只是把明文信息變成了不可見的字符串。但是其實只要用一些工具就可以把base64編碼解成明文,所以不要在JWT中放入涉及私密的信息。

3、JWT的用法

客戶端接收服務器返回的JWT,將其存儲在Cookie或localStorage中。

此后,客戶端將在與服務器交互中都會帶JWT。如果將它存儲在Cookie中,就可以自動發送,但是不會跨域,因此一般是將它放入HTTP請求的Header Authorization字段中。

當跨域時,也可以將JWT放置於POST請求的數據主體中。

三、JWT問題和趨勢

1、JWT默認不加密,但可以加密。生成原始令牌后,可以使用該令牌再次對其進行加密。

2、當JWT未加密時,一些私密數據無法通過JWT傳輸。

3、JWT不僅可用於認證,還可用於信息交換。善用JWT有助於減少服務器請求數據庫的次數。

4、JWT的最大缺點是服務器不保存會話狀態,所以在使用期間不可能取消令牌或更改令牌的權限。也就是說,一旦JWT簽發,在有效期內將會一直有效。

5、JWT本身包含認證信息,因此一旦信息泄露,任何人都可以獲得令牌的所有權限。為了減少盜用,JWT的有效期不宜設置太長。對於某些重要操作,用戶在使用時應該每次都進行身份驗證。

6、為了減少盜用和竊取,JWT不建議使用HTTP協議來傳輸代碼,而是使用加密的HTTPS協議進行傳輸。

四、JWT的使用DEMO

4.1、創建Maven項目

1、項目

項目類型:Maven
groupId:com.atguigu
artifactId:jwt

2、基本依賴

<dependencies>
    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.7.0</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.6</version>
    </dependency>
    
     <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

3、創建Member.java

package com.atguigu.jwt.entity;
@Data
public class Member {
    private String id;
    private String nickname;
    private String avatar;
}

4.2、創建工具類

1、創建JWT工具類

package com.atguigu.jwt.util;
public class JwtUtils {
    public static final String SUBJECT = "guli-user";
    //秘鑰
    public static final String APP_SECRET = "79e7c69681b8270162386e6daa53d1dc";
    //過期時間,毫秒,30分鍾
    public static final long EXPIRE = 1000 * 60 * 30;
    /**
     * 生成Jwt令牌
     * @return
     */
    public static String generateJwt(Member member){
        String token = Jwts.builder()
                .setHeaderParam("typ", "JWT") //令牌類型
                .setHeaderParam("alg", "HS256") //簽名算法
                .setSubject(SUBJECT) //令牌主題
                .setIssuedAt(new Date()) //簽發時間
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) //過期時間
                .claim("id", member.getId())
                .claim("nickname", member.getNickname())
                .claim("avatar", member.getAvatar())
                .signWith(SignatureAlgorithm.HS256, APP_SECRET).compact();
        return token;
    }
    /**
     * 校驗jwt
     * @param jwtToken
     * @return
     */
    public static Claims checkJwt(String jwtToken){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return claims;
    }
}

2、測試用例

package com.atguigu.jwt;
public class JwtTest {
    @Test
    public void testGenerateJwt(){
        Member member = new Member();
        member.setId("10000");
        member.setNickname("Helen");
        member.setAvatar("1.png");
        String jwt = JwtUtils.generateJwt(member);
        System.out.println(jwt);
    }
   @Test
    public void testCheckJwt(){
        Claims claims = JwtUtils.checkJwt("jwt字符串");
        String id = (String)claims.get("id");
        String nickname = (String)claims.get("nickname");
        String avatar = (String)claims.get("avatar");
        System.out.println(id);
        System.out.println(nickname);
        System.out.println(avatar);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM