jjwt源码解析
jjwt源碼解析
author:zxw
email:502513206@qq.com
@ Jishou University
1.前言
最近在做一個(gè)jwt授權(quán)服務(wù),其實(shí)也就是給請求的用戶生成一個(gè)token,不過關(guān)于token的驗(yàn)證并不在我服務(wù)負(fù)責(zé),而是由網(wǎng)關(guān)去統(tǒng)一處理。jwt之前也用過幾次,不過不是很熟悉只知道是通過base64Url算法進(jìn)行加密,這次剛好用到了所以來看看jjwt的實(shí)現(xiàn)。
2.源碼解析
在java中導(dǎo)入jjwt的包就可以使用包中提供的Builder生成jwt的token,以下是基礎(chǔ)的用法。
JwtBuilder builder = Jwts.builder().setHeader(header) // 頭部信息.setId(uuid) //id:是JWT的唯一標(biāo)識.setSubject(subject) //Subject:可以存放用戶信息.setIssuer(appId) //Issuer:簽發(fā)者.setIssuedAt(now) //IssuedAt:jwt的簽發(fā)時(shí)間.signWith(signatureAlgorithm, secretKey);通過名字可以看到,是使用的builder構(gòu)造模式生成,默認(rèn)給我們返回一個(gè)DefaultJwtBuilder對象
JwtBuilder
public static JwtBuilder builder() {return new DefaultJwtBuilder();}DefaultJwtBuilder我們知道jwt是由header,payload,Signature三部分組成。
public class DefaultJwtBuilder implements JwtBuilder {private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();private Header header; // Headerprivate Claims claims;private String payload; // 載體private SignatureAlgorithm algorithm; // 簽名算法private Key key;private byte[] keyBytes;private CompressionCodec compressionCodec; // 壓縮算法 }Header頭部由兩部分信息組成,一個(gè)是類型,一個(gè)是加密的算法,具體類型如下。
{'typ': 'JWT','alg': 'HS256' }Header在jjwt中有個(gè)Header接口表示頭部,可以看到Header的固定key
public interface Header<T extends Header<T>> extends Map<String,Object> {/** JWT {@code Type} (typ) value: <code>"JWT"</code> */public static final String JWT_TYPE = "JWT";/** JWT {@code Type} header parameter name: <code>"typ"</code> */public static final String TYPE = "typ";/** JWT {@code Content Type} header parameter name: <code>"cty"</code> */public static final String CONTENT_TYPE = "cty";/** JWT {@code Compression Algorithm} header parameter name: <code>"zip"</code> */public static final String COMPRESSION_ALGORITHM = "zip";/** JJWT legacy/deprecated compression algorithm header parameter name: <code>"calg"</code>* @deprecated use {@link #COMPRESSION_ALGORITHM} instead. */@Deprecatedpublic static final String DEPRECATED_COMPRESSION_ALGORITHM = "calg"; }DefaultHeaderjjwt中默認(rèn)會使用該類,當(dāng)然我們也能自己實(shí)現(xiàn)Header接口或者繼承該類實(shí)現(xiàn)自定義的Header,可以看到Header其實(shí)就是一個(gè)Map,我們也能往頭部添加我們自定義的數(shù)據(jù)
public class DefaultHeader<T extends Header<T>> extends JwtMap implements Header<T> { }接下來就是第二部分載體了,在jjwt中我們可以傳入json的payload載體也可以用claim封裝我們的載體,二者只能選一個(gè)。
Claims可以看到cliams同樣是個(gè)map,我們在使用setSubject等方法時(shí),實(shí)際上就是往下面的key設(shè)置對應(yīng)的Value
public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */public static final String ISSUER = "iss";/** JWT {@code Subject} claims parameter name: <code>"sub"</code> */public static final String SUBJECT = "sub";/** JWT {@code Audience} claims parameter name: <code>"aud"</code> */public static final String AUDIENCE = "aud";/** JWT {@code Expiration} claims parameter name: <code>"exp"</code> */public static final String EXPIRATION = "exp";/** JWT {@code Not Before} claims parameter name: <code>"nbf"</code> */public static final String NOT_BEFORE = "nbf";/** JWT {@code Issued At} claims parameter name: <code>"iat"</code> */public static final String ISSUED_AT = "iat";/** JWT {@code JWT ID} claims parameter name: <code>"jti"</code> */public static final String ID = "jti"; }最后一步就是Jwts.builder().signWith(signatureAlgorithm, secretKey);在該方法中指定我們的加密的算法就是頭部{"alg":"HS256"}所對應(yīng)的值
public JwtBuilder signWith(SignatureAlgorithm alg, Key key) {Assert.notNull(alg, "SignatureAlgorithm cannot be null.");Assert.notNull(key, "Key argument cannot be null.");// 加密算法,默認(rèn)使用HS256this.algorithm = alg;// secret,我們與客戶端規(guī)定的密鑰this.key = key;return this;} @Overridepublic String compact() {// 判斷載體是否為空if (payload == null && Collections.isEmpty(claims)) {throw new IllegalStateException("Either 'payload' or 'claims' must be specified.");}// 判斷payload和claim是否都不為空if (payload != null && !Collections.isEmpty(claims)) {throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");}// key和keybytes是否都不為空if (key != null && keyBytes != null) {throw new IllegalStateException("A key object and key bytes cannot both be specified. Choose either one.");}// 如果為空,生成默認(rèn)的HeaderHeader header = ensureHeader();Key key = this.key;// 如果未指定密鑰算法,則生成默認(rèn)的算法if (key == null && !Objects.isEmpty(keyBytes)) {key = new SecretKeySpec(keyBytes, algorithm.getJcaName());}JwsHeader jwsHeader;if (header instanceof JwsHeader) {jwsHeader = (JwsHeader)header;} else {jwsHeader = new DefaultJwsHeader(header);}// 設(shè)置頭部的alg對應(yīng)的算法類型if (key != null) {jwsHeader.setAlgorithm(algorithm.getValue());} else {//no signature - plaintext JWT:jwsHeader.setAlgorithm(SignatureAlgorithm.NONE.getValue());}// 設(shè)置壓縮算法if (compressionCodec != null) {jwsHeader.setCompressionAlgorithm(compressionCodec.getAlgorithmName());}// 頭部進(jìn)行base64Url加密String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json.");String base64UrlEncodedBody;// 對載體進(jìn)行base64Url加密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.");}String jwt = base64UrlEncodedHeader + JwtParser.SEPARATOR_CHAR + base64UrlEncodedBody;// 對簽名進(jìn)行base64Url加密if (key != null) { //jwt must be signed:// 生成Signer,下發(fā)給客戶端的密鑰JwtSigner signer = createSigner(algorithm, key);// 對前兩部分進(jìn)行base64Url加密String base64UrlSignature = signer.sign(jwt);// 組合jwt += JwtParser.SEPARATOR_CHAR + base64UrlSignature;} else {// no signature (plaintext), but must terminate w/ a period, see// https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-6.1jwt += JwtParser.SEPARATOR_CHAR;}// 返回tokenreturn jwt;}可以看到j(luò)wt的組成,對header進(jìn)行base64Url加密 + payload的base64Url加密 + (header + payload + secret)三部分加密組成。
總結(jié)
- 上一篇: beyond compare 用法
- 下一篇: 猿如意|IntelliJ IDEA Co