JWT(Json web token)認證詳解


JWT的定義:

  JWT是一種用於雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規范。JWT作為一個開放的標准(RFC 7519),定義了一種簡潔的,自包含的方法用於通信雙方之間以Json對象的形式安全的傳遞信息。因為數字簽名的存在,這些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘鑰對進行簽名。

JWT特點:
  簡潔(Compact): 可以通過URL,POST參數或者在HTTP header發送,因為數據量小,傳輸速度也很快
  自包含(Self-contained):負載中包含了所有用戶所需要的信息,避免了多次查詢數據庫

JWT結構:

JWT主要包含Header 頭部  Payload 負載  Signature 簽名,順序是 header.payload.signature 三部分之間用英語句號’.'隔開  
 

Header頭部

頭部包含了兩部分,token 類型(“JWT”)和采用的加密算法(HMAC SHA256或者RSA等等)

例如:

然后,用Base64對這個JSON編碼就得到JWT的第一部分

Payload負載

這部分就是我們存放信息的地方了,你可以把用戶 ID 等信息放在這里,JWT 規范里面對這部分有進行了比較詳細的介紹,常用的由 iss(簽發者),exp(過期時間),sub(面向的用戶),aud(接收方),iat(簽發時間)。

同樣的,它會使用 Base64 編碼組成 JWT 結構的第二部分。

Signature簽名

  前面兩部分都是使用 Base64 進行編碼的,即前端可以解開知道里面的信息。Signature 需要使用Base64編碼后的 header 和 payload 以及我們提供的一個密鑰,然后使用 header 中指定的簽名算法(HS256)進行簽名。簽名的作用是保證 JWT 沒有被篡改過。三個部分通過.連接在一起就是我們的 JWT 了,它可能長這個樣子,長度貌似和你的加密算法和私鑰有關系。

eyJhbGciOiJIUzI1NiIsIlR5cGUiOiJKd3QiLCJ0eXAiOiJKV1QifQ.eyJsb2dpblRpbWUiOiIyMDIxLTEwLTI3VDE1OjIxOjU4LjU3OCIsInVzZXJOYW1lIjoi5rGf5Y2XIiwiZXhwIjoxNjM1MzIxMTE4fQ.lUojZpIGx0a65s5FrgYlQio0vf3jOuqWOTP-DUjzGh0
注意:secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了

JSON Web Tokens是如何工作的?

一般是在請求頭里加入Authorization,並加上Bearer標注:

fetch('api/user/1', {
  headers: {
    'Authorization': 'Bearer ' + token
  }
})

服務端會驗證token,如果驗證通過就會返回相應的資源。整個流程就是這樣的:

優點

  • 因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
  • 因為有了payload部分,所以JWT可以在自身存儲一些其他業務邏輯所必要的非敏感信息。
  • 便於傳輸,jwt的構成非常簡單,字節占用很小,所以它是非常便於傳輸的。
  • 它不需要在服務端保存會話信息, 所以它易於應用的擴展

安全相關

  • 不應該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
  • 保護好secret私鑰,該私鑰非常重要。
  • 如果可以,請使用https協議

最后附上Token工具類

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenUtil {

    /**
     * token過期時間
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000;
    /**
     * token秘鑰
     */
    private static final String TOKEN_SECRET = "secret";


    /**
     * 生成token,30分鍾過期
     *
     * @param userName  用戶名
     * @param loginTime 登錄時間
     * @return 生成的token
     */
    public static String sign(String userName, LocalDateTime loginTime) {
        try {
            // 設置過期時間
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            System.out.println(date);
            // 私鑰和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 設置頭部信息
            Map<String, Object> header = new HashMap<>(3);
            header.put("Type", "Jwt");
            header.put("alg", "HS256");
            // 返回token字符串
            return JWT.create()
                    .withHeader(header)
                    // 設置token中需要加載的用戶信息 存儲自己想要留給前端的內容
                    .withClaim("userName", userName)
                    .withClaim("loginTime", loginTime.toString())
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 檢驗token是否正確
     */
    public static boolean verify(String token) {
        try {
            //設置簽名的加密算法:HMAC256
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 獲取token中信息 userName
     */

    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();

        } catch (JWTDecodeException e) {
            e.printStackTrace();
        }
        return null;
    }
}


免責聲明!

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



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