先給出JWT的官方文檔html
JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且獨立的方式,用於在各方之間做爲JSON對象安全地傳輸信息。java
JWT令牌由Header、Payload、Signature三部分組成,每部分之間用點號分隔,一般的形式爲xxxxx.yyyyy.zzzzz
,下面分別對每部分作詳細介紹。git
Header一般由兩部分組成:令牌的類型,即JWT,以及使用的簽名算法,例如HMAC SHA256或RSA。github
{ "alg": "HS256", "typ": "JWT" }
這個JSON被編碼爲Base64Url,造成JWT的第一部分。web
JWT的第二部分是有效載荷,其中包含聲明( claims)。聲明包含實體(一般是用戶)和其餘自定義信息。聲明有三種類型:registered, public和private claims 。算法
請注意:聲明名稱只有三個字符,由於JWT須要保持簡潔。數據庫
Payload通過Base64Url編碼,造成JWT的第二部分。json
請注意:對於JWT令牌,雖然能夠防止被篡改,但任何人均可以讀取。除非加密,不然不要將祕密信息放在JWT的有效載荷或頭元素中。api
Signature由Base64Url加密的Header、Payload再使用Header中指定的算法加密以後再和secret組成。跨域
若是要使用HMACSHA256算法,將按如下方式建立簽名:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Signature用於驗證消息在此過程當中未被更改,而且,在使用私鑰簽名的令牌的狀況下,它還能夠驗證JWT的發件人的身份。
最後將JWT的三部分由點號分隔做爲一個字符串,其能夠在HTML和HTTP環境中輕鬆傳遞,而且比基於XML的標準的Token(如SAML)更加簡潔。
在身份驗證中,當用戶使用其憑據成功登陸時,將返回JSON Web Token。因爲令牌是憑證,所以必須很是當心以防止出現安全問題。通常狀況下,您不該該將令牌保留的時間超過要求。
每當用戶想要訪問受保護的路由或資源時,用戶發送JWT到相應的地址,一般在Authorization標頭中。請求頭的的內容應以下所示:
Authorization: Bearer <token>
在某些狀況下,這能夠是無狀態受權機制。服務器的受保護路由將檢查Authorization
標頭中的有效JWT ,若是存在,則容許用戶訪問受保護資源。若是JWT包含必要的數據,則能夠減小查詢數據庫以進行某些操做的須要,儘管可能並不是老是如此。
若是在標Authorization
頭中發送Token,則跨域資源共享(CORS)將不會成爲問題,由於它不使用cookie。
下圖顯示瞭如何獲取JWT並用於訪問API或資源:
請注意:使用JWT時,Token中包含的全部信息都會向用戶或其餘方公開,即便他們沒法更改。因此您不該該在令牌中放置祕密信息。
JWT的java實現很是多,詳細何以查看官方文檔。
其中經常使用的有com.auth0.java-jwt和io.jsonwebtoken.jjwt
這裏我採用 jjwt 做爲演示,由於他的Github中的Star比較多。
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.10.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.10.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.10.5</version> <scope>runtime</scope> </dependency> <!-- Uncomment this next dependency if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms: <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> <scope>runtime</scope> </dependency> -->
//Sample method to construct a JWT public static String createJWT(String id, String issuer, String subject, long ttlMillis) { //The JWT signature algorithm we will be using to sign the token SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); //We will sign our JWT with our ApiKey secret byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary( APP_ID + APP_SECRET); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); //Let's set the JWT Claims JwtBuilder builder = Jwts.builder().setId(id) .setIssuedAt(now) .setSubject(subject) .setIssuer(issuer) .signWith(signatureAlgorithm, signingKey); //if it has been specified, let's add the expiration if (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis; Date exp = new Date(expMillis); builder.setExpiration(exp); } //Builds the JWT and serializes it to a compact, URL-safe string return builder.compact(); }
//Sample method to validate and read the JWT public static Claims parseJWT(String jwt) { //This line will throw an exception if it is not a signed JWS (as expected) Claims claims = Jwts.parser() .setSigningKey(DatatypeConverter.parseBase64Binary(APP_ID + APP_SECRET)) .parseClaimsJws(jwt).getBody(); // System.out.println("ID: " + claims.getId()); // System.out.println("Subject: " + claims.getSubject()); // System.out.println("Issuer: " + claims.getIssuer()); // System.out.println("Expiration: " + claims.getExpiration()); return claims; }
其中APP_ID
和APP_SECRET
能夠自定義爲你想要的任何值,可是不能過於簡單。
你會發現咱們再使用的時候沒有設置Header的值,由於jjwt爲了咱們使用方便會根據使用的簽名算法或壓縮算法自動設置它們。
@Test public void createJWT(){ String jwt = JWTUtil.createJWT("1", "111", "admin", JWTUtil.DAY_TTL); System.out.println(jwt); } @Test public void parseJWT(){ Claims claims = JWTUtil.parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwiaWF0IjoxNTQ4Mjk1NjQ0LCJzdWIiOiJhZG1pbiIsImlzcyI6IjExMSIsImV4cCI6MTU0ODMzODg0NH0.WRkyeG3MfVor02Ya4732fgGydXhtkkKSDwbxOIZ2i9Y"); System.out.println(claims); }
若是想使用jjwt更復雜的功能或者其餘的Java實現能夠去他們相應的Github上學習。