Json Web Token


一、認識JWT(Json Web Token)

JSON Web Token(縮寫 JWT)是目前最流行的跨域認證解決方案,一般來說如果是使用session或者cookie來實現,但是這兩者都有一定的局限性。而我們使用JWT去實現跨域認證的話,就可以將JWT放在請求頭里面(也有人會把它放在post請求的數據體里,但是這種方法比較少見)。

  1.JWT的數據結構

JWT解析出來之后其實就是一個Json,但是在傳送的過程中,它是一串很長的字符串,中間用“.”分割成三個部分

  • Header(頭部)
  • Payload(負載)
  • Signature(簽名)

寫成一行就是

Header.Payload.Signature

舉一個我在真正開發時遇到的一個JWT,里面的id_token就是一個JWT,可以看到它就是用兩個“.”去分割開的。

 

 

 

  2.Header(頭部)

Header 部分是一個 JSON 對象,描述 JWT 的元數據。

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

上面代碼中,alg屬性表示簽名的算法(algorithm),默認是 HMAC SHA256(寫成 HS256);typ屬性表示這個令牌(token)的類型(type),JWT 令牌統一寫為JWT

最后,將上面的 JSON 對象使用 Base64URL 算法成字符串。說到這個,如果你的簽名算法是別的算法的話,去解析JWT的時候會報錯

Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance

這時候你要去檢查一下你的密鑰是否正確,我當時的情況就是公鑰搞錯了,不過我看網上也有人說什么可以設置一下算法的類型,但是看不懂是怎么操作的,全網就搜到了那個方法,全都是一模一樣,復制來復制去的,很沒意思。

  3.Payload(負載)

Payload是JWT最重要的數據,里面會攜帶很多信息,我們要實現登錄認證一般都在里面拿取到我們想要的數據。JWT 規定了7個官方字段供選用。

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

除了官方字段,我們還可以在生成JWT的時候定義部分私有字段名,下面是我工作是遇到的JWT,他們就定義了自己的私有字段,將payload解析之后就是下面的圖片

  4.Signature(簽名)

Signature 部分是對前兩部分的簽名,防止數據篡改。

首先,需要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。然后,使用 Header 里面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。

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

算出簽名以后,把 Header、Payload、Signature 三個部分拼成一個字符串,每個部分之間用"點"(.)分隔,就可以返回給用戶。

  5.JWT的使用

一般是放在請求頭里面,注意“Bearer”和“token”之間有一個空格。

Authorization: Bearer <token>

二、解析JWT

解析JWT網上有很多個jar可以拿來使用,我這里使用的jose4j來解析。

    /**
     * 驗證Jwt並拿到email值
     *
     * @param jwtTicket Jwt票據
     * @param publicKeyStr 公鑰
     */
    public String validateAndGetToken(String jwtTicket, String publicKeyStr) throws Exception {

        JsonWebSignature jws = new JsonWebSignature();
        jws.setCompactSerialization(jwtTicket);
        JsonWebKey jsonWebKey = JsonWebKey.Factory.newJwk(publicKeyStr);
        String keyId = jsonWebKey.getKeyId();
        jws.setKey(jsonWebKey.getKey());

        boolean verifySignature = jws.verifySignature();
        if (!verifySignature) {
            throw new Exception("Invalid signature!");
        }

        String payload = jws.getPayload();
        JwtClaims claims = JwtClaims.parse(payload);
        NumericDate expirationTime = claims.getExpirationTime();
        Map<String, Object> claimsMap = claims.getClaimsMap();
        if (expirationTime == null) {
            logWarn("Invalid signature!");
            return null;
        }
        if (!expirationTime.isAfter(NumericDate.now())) {
            logWarn("Jwt ticket expired!");
            return null;
        }
        String username = (String) claimsMap.get("email");
        return username;
    }

這里claimsMap.get("email")就是拿到郵箱地址,因為我做的是郵箱的單點登錄,所以這里是email,根據具體情況去獲取具體的字段就可以了。

 參考鏈接

http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html


免責聲明!

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



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