pom.xml文件
<!-- Base64編碼時用到 --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency> <!-- 核心包 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.8.0</version> </dependency>
粗略的實現類:
import java.util.Date; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.util.encoders.Base64; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureException; public class JWTTest { public static final String JWT_SECERT = "b3d4e546a7a94da59cb193203116c06f3acff0e258054ea0a7bce8717e44b27a"; /** * 創建key * @return */ public static SecretKey generalKey() { byte[] encodeKey = Base64.decode(JWT_SECERT); SecretKey key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES"); return key; } /** * 簽發JWT * * @param jti jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊 * @param sub jwt所面向的用戶 * @param expiredTimeAt 過期時間(當前時間ms+要過期時間ms),單位ms * @return */ public static String createJWT(String jti, String sub, long expiredTimeAt) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; Long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); SecretKey secretKey = generalKey(); JwtBuilder builder = Jwts.builder() .claim("name", "xxxx") // 自定義聲明(可以定義多個,也可以不定義) .setId(jti) .setSubject(sub) .setIssuedAt(now) // jwt的簽發時間 .signWith(signatureAlgorithm, secretKey); if (expiredTimeAt > 0) { Date expDate = new Date(expiredTimeAt); builder.setExpiration(expDate); } return builder.compact(); } /** * 校驗jwtStr * * @param jwtStr * @return * @throws ExpiredJwtException,SignatureException,Exception token已過期,簽名校驗失敗,其它錯誤 */ public static boolean validateJWT(String jwtStr) { boolean flag = false; try { parseJWT(jwtStr); flag = true; } catch (ExpiredJwtException e) { // TODO 可以用日志來記錄錯誤信息 } catch (SignatureException e) { // TODO 可以用日志來記錄錯誤信息 } catch (Exception e) { // TODO 可以用日志來記錄錯誤信息 } return flag; } /** * * 解析JWT字符串 * * @param jwt * @return claims,包括公告聲明,自定義聲明 * @throws ExpiredJwtException,SignatureException,Exception token已過期,簽名校驗失敗,其它錯誤 */ public static Claims parseJWT(String jwt) throws ExpiredJwtException,SignatureException,Exception { SecretKey secretKey = generalKey(); return Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); } public static void main(String[] args){ String jwtString = createJWT("1001", "huang", System.currentTimeMillis() + 10000); System.out.println(jwtString); // Claims claims = parseJWT(jwtString); // System.out.println(claims.getId()); // System.out.println(claims.getSubject()); // System.out.println(claims.get("name")); // 自定義的 try { System.out.println(parseJWT(jwtString)); } catch (ExpiredJwtException e) { System.out.println("token已過期"); } catch (SignatureException e) { System.out.println("簽名校驗失敗"); } catch (Exception e) { System.out.println("其它錯誤"); } } }
在JWT創建過程中,以下部分屬於payload(荷載)部分
.claim("name", "xxxx") // 自定義聲明(可以定義多個,也可以不定義) .setId(jti) .setSubject(sub) .setIssuedAt(now) // jwt的簽發時間
其實這部分還有另外一種方式,payload應該是json的字符串形式,這個優先級別高於上面的設置方式。(本人未親自測試過,我是看源碼得出的猜測)
Jwts.builder().setPayload(payload)
以下是設置payload的一部分源碼。出處DefaultJwtBuilder.class的compact()里大概303行
if (compressionCodec != null) { byte[] bytes; try { bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Unable to serialize claims object to json."); } base64UrlEncodedBody = TextCodec.BASE64URL.encode(compressionCodec.compress(bytes)); } else { base64UrlEncodedBody = this.payload != null ? TextCodec.BASE64URL.encode(this.payload) : base64UrlEncode(claims, "Unable to serialize claims object to json.");
重點是這句:bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
上面的JWTTest.java類寫的很粗糙,有時間再改進。
--------------------------------------------------------2017年12月11日修改--------------------------------------------------------
忘記補充了,jwt一旦簽發出去,不到失效時間,該token會一直生效。
如果想要手動讓其失效,可以將該token保存在數據庫或者緩存中。
比如存放在redis中,並同時設置失效時間,請求接收到該token后,
與redis里的token進行匹配。
--------------------------------------------------------2017年12月26日修改--------------------------------------------------------
修改版鏈接:http://blog.csdn.net/h996666/article/details/78902545
讓jwt失效還有一個辦法就是更換密鑰key,一旦更換會導致之前簽發出去的所有jwt失效