latex中插入程式碼
JWT(即json web token),大家先看下面這張圖
大家可以觀察到,jwt String就是生成後的jwt字符集,其中有兩個 "."(注意:jwt校驗會對"."個數校驗,多或少都會校驗失敗),被"."分割的就是jwt的三個構成部分,即:header、payload、sign。
接下來,給大家講下jwt的生成規則和校驗規則
JWT生成規則:
1、設定加密方式、claims資訊(即payload)和signingkey
2、設定加密方式為header,並進行base編碼
3、設定claims資訊為payload,並進行base64編碼
4、對header和payload用"."拼接成jwt,,使用signingkey按照加密方式進行加密,生成sign
5、對Jwt和sign用"."生成最終的jwt
JWT校驗規則:
1、設定jwt和signingkey
2、按"."對jwt分成三部分,即:header、payload、sign
3、取第一部分進行base64解碼,獲取加密方式
4、取第二部分進行base64解碼,獲取業務引數,即payload
5、使用加密方式和signingkey建立校驗器,對header+payload進行加密,並與sign(即第三部分)進行對比
6、取出payload的有效期進行校驗,是否過期
7、通過校驗,返回claims資訊
附:
1、進行base64編碼時,會判斷是否為android客戶端,使用base64的庫不一樣,這點可以自行看原始碼。
2、jwt會對生成的base64字符集的特殊符號進行轉換,"-"換為"+",“_”換位"/",去掉尾部"="
3、jwt校驗時,會判斷是否有且只有兩個".",否則校驗失敗
原理總結:
1、三部分裡的header和payload是獨立的,無須signingkey,只需base64解碼即可看到payload的資訊,所以千萬不要在payload裡放敏感資訊
2、如果是使用jwt作為登入態校驗,建議使用對稱加密,因為非對稱解密效率相對較慢,較多請求下會影響效能
3、因jwt是無狀態的,之前見很多同學使用redis進行儲存,我不是很明白,這豈不是違反了jwt當初的設計原則
4、保證金鑰不要洩露,否則jwt可以被偽造
5、必要情況下,建議使用https
另附上個人的程式碼供大家參考
package com.yhc.demo.plugin; import java.io.UnsupportedEncodingException; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureException; import io.jsonwebtoken.UnsupportedJwtException; /** * JwtToken工具類 */ @Configuration public class JwtService { private static final Logger log = LoggerFactory.getLogger(JwtService.class); @Value("${jwt.secret:123456}") private String secret; @Value("${jwt.expiration:60}") private Long expiration; /** * 生成token * * @param username * @return token */ public String generateToken(String username) { Claims claims = Jwts.claims(); claims.setIssuer(username); // jwt發行人 claims.setIssuedAt(new Date()); // jwt生成時間 claims.setExpiration(getExp()); // jwt過期時間 claims.setSubject("auth"); // jwt主題 claims.setAudience("yhc"); // jwt接受方 claims.setId("uuid"); // jwt唯一身份標識 claims.setNotBefore(new Date()); // jwt在此之前不可用 return generateToken(claims); } /** * 重新整理token * * @param old token * @return new token */ public String refreshToken(String token) { Claims claims = validToken(token); if (claims == null) { return null; } claims.setIssuedAt(new Date()); claims.setExpiration(getExp()); return generateToken(claims); } /** * 根據token獲取發行人 * * @param token * @return issuer */ public String getIssuer(String token) { Claims claims = validToken(token); return claims.getIssuer(); } /** * 校驗jwtToken,如無效,則返回Null,反之,返回負載物件 */ private Claims validToken(String token) { Claims claims = getClaimsFromToken(token); if (claims != null) { Date exp = claims.getExpiration(); if (exp.before(new Date())) { log.warn("# jwtToken已失效:{}", token); throw new RuntimeException("invalid token"); } } return claims; } /** * 從token中獲取JWT中的負載引數 */ private Claims getClaimsFromToken(String token) { Claims claims = null; try { claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } catch (Exception e) { log.warn("# jwtToken格式驗證失敗:{}", token, e); throw new RuntimeException("token verification failed"); } return claims; } /** 根據負載引數生成token */ private String generateToken(Claims claims) { return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact(); } /** 獲取token有效期 */ private Date getExp() { return new Date(System.currentTimeMillis() + expiration * 1000); } public static void main(String[] args) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException, UnsupportedEncodingException { String username = "yhc"; Claims claims = Jwts.claims(); claims.setIssuer(username); // jwt發行人 claims.setIssuedAt(new Date()); // jwt生成時間 claims.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); // jwt過期時間 claims.setSubject("test"); // jwt主題 claims.setAudience("yhc"); // jwt接受方 claims.setId("uuid"); // jwt唯一身份標識 // claims.setNotBefore(new Date()); // jwt在此之前不可用 String visitTK = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, "sad12f").compact(); System.out.println(visitTK);// SystemValue.JWT_HEADER_VALUE_PREFIX + Claims claimsDecode = Jwts.parser().setSigningKey("sad12f").parseClaimsJws(visitTK).getBody(); System.out.println(claimsDecode.getIssuer()); } }
以上純為個人總結,如有錯誤,還請指出,謝謝。