天天看點

使用JWT生成Token進行接口鑒權實作方法利用JWT進行鑒權的思路JWT介紹使用的工具類參考

利用JWT進行鑒權的思路

  1. 使用者發起登入請求。
  2. 伺服器使用私鑰建立一個jwt字元串,作為token;
  3. 伺服器将這個token傳回給浏覽器;
  4. 在後續請求中,token作為請求頭的内容,發給服務端。
  5. 服務端拿到token之後進行解密,正确解密表示此次請求合法,驗證通過;解密失敗說明Token無效或者已過期
  6. 傳回響應的資源給浏覽器
    使用JWT生成Token進行接口鑒權實作方法利用JWT進行鑒權的思路JWT介紹使用的工具類參考

JWT介紹

什麼是JWT

JSON Web令牌(JWT)是一種開放标準(RFC 7519),它定義了一種緊湊且自包含的方式,以JSON對象的形式在通信雙方之間安全地傳輸資訊。由于該資訊是數字簽名的,是以可以對其進行驗證和信任。jwt可以使用散列消息驗證碼(使用HMAC算法),也可以使用RSA或ECDSA公鑰/私鑰對簽名。

應用場景

  • 授權: 這是使用JWT最常見的場景。一旦使用者登入,每個後續請求将包括JWT,允許使用者通路該令牌允許的路由、服務和資源。單點登入SSO是目前JWT廣泛使用的一個特性,因為它的開銷很小,而且可以輕松地跨不同的領域使用。
  • 資訊交換:JSON Web Tokens 是在各方之間安全地傳輸資訊的一種好方法。因為JWT可以簽名(例如,使用公鑰/私鑰對),是以可以确定發送方就是他們所說的那個人。此外,由于使用頭和有效負載計算簽名,您還可以驗證内容沒有被篡改。

優點

  • 簡潔(Compact): 可以通過GET參數、POST參數、HTTP header發送,因為資料量小,傳輸速度也很快
  • 自包含(Self-contained):負載中包含了所有使用者所需要的資訊,避免了多次查詢資料庫
  • 因為Token是以JSON加密的形式儲存在用戶端的,是以JWT是跨語言的,原則上任何web形式都支援。
  • 不需要在服務端儲存會話資訊,特别适用于分布式微服務。

JWT的結構

JWT是由三段資訊構成的,将這三段資訊文本用**.**連接配接一起就構成了JWT字元串。

JWT通常長成這樣:xxxx.yyyy.zzzzz

實際示例如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiLlvKDkuIkiLCJleHAiOjE2MzI0NzQxMzQsInVzZXJuYW1lIjoi5byg5LiJIn0.r1UipPk6_69r5Cd7kPoz6rM4NDKDF37su0YOWVGOZ6U

JWT包含了三部分:

  • Header 頭部: 通常由兩部分組成:令牌的類型,即JWT,以及使用的簽名算法,如HMAC SHA256或RSA。
  • Payload 負載: 有效負載,通信雙方要交換的内容
  • Signature 簽名/簽證
使用JWT生成Token進行接口鑒權實作方法利用JWT進行鑒權的思路JWT介紹使用的工具類參考

Header

通常由兩部分組成:令牌的類型,即JWT,以及使用的簽名算法,如HMAC SHA256或RSA。

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

加密算法是單向函數雜湊演算法,常見的有MD5、SHA、HAMC。

  • *MD5(message-digest algorithm 5)資訊-摘要算法:廣泛用于加密和解密技術,常用于檔案校驗。不管檔案多大,經過MD5後都能生成唯一的MD5值
  • SHA (Secure Hash Algorithm)安全雜湊演算法,數字簽名等密碼學應用中重要的工具,安全性高于MD5
  • HMAC (Hash Message Authentication Code)散列消息驗證碼,基于密鑰的Hash算法的認證協定。用公開函數和密鑰産生一個固定長度的值作為認證辨別,用這個辨別鑒别消息的完整性。常用于接口簽名驗證

Payload

有效負載就是存放通信雙方要交換的内容的地方

有效資訊包含三個部分

  • Registered claims 标準中注冊的聲明
  • Public claims 公共的聲明
  • Private claims 私有的聲明

标準中注冊的聲明:這些是一組預定義的聲明,不是強制性的,但推薦使用這些聲明,以提供一組有用的、可互操作的聲明。

  • iss: jwt簽發者
  • sub: 面向的使用者(jwt所面向的使用者)
  • aud: 接收jwt的一方
  • exp: 過期時間戳(jwt的過期時間,這個過期時間必須要大于簽發時間)
  • nbf: 定義在什麼時間之前,該jwt都是不可用的.
  • iat: jwt的簽發時間
  • jti: jwt的唯一身份辨別,主要用來作為一次性token,進而回避重播攻擊。

公共的聲明 :

公共的聲明可以添加任何的資訊,一般添加使用者的相關資訊或其他業務需要的必要資訊. 但不建議添加敏感資訊,因為該部分在用戶端可解密.

私有的聲明 :

私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感資訊,因為base64是對稱解密的,意味着該部分資訊可以歸類為明文資訊。

Signature

jwt的第三部分是一個簽證資訊

這個部分需要base64加密後的header和base64加密後的payload使用.連接配接組成的字元串,然後通過header中聲明的加密方式進行加鹽secret組合加密,然後就構成了jwt的第三部分。

密鑰secret是儲存在服務端的,服務端會根據這個密鑰進行生成token和進行驗證,是以需要保護好。

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

使用的工具類

導入依賴

<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.11.0</version>
		</dependency>
           

工具類源碼

public class JwtUtil {
	public static void main(String[] args) {
        String secret = "123456";
        String username = "張三";
        String token = sign(username, secret);
        printMsg("token:%s", token);
        printMsg("username:%s", getUsername(token));
        printMsg("verify:%s", verify(token, username, secret));
    }

    private static void printMsg(String template, Object... args) {
        System.out.println(String.format(template, args));
    }
    
    public static final long EXPIRE_TIME = 1800000L;

    public JwtUtil() {
    }

    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            verifier.verify(token);
            return true;
        } catch (Exception var6) {
            return false;
        }
    }

    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException var2) {
            return null;
        }
    }

    public static String sign(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + 1800000L);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
    }

    public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException {
        String accessToken= request.getParameter("token");
        if (accessToken== null) {
            accessToken= request.getHeader("X-Access-Token");
        }
        String username = getUsername(accessToken);
        if (oConvertUtils.isEmpty(username)) {
            throw new JeecgBootException("未擷取到使用者");
        } else {
            return username;
        }
    }
}
           

參考

JWT官網

JWT(Java版)的github

繼續閱讀