Java JWT: JSON Web Token for Java and Android
JJWT的是在JVM上創(chuàng)建和驗(yàn)證JSON Web Token(JWTs)的庫(kù)。
JJWT是基于JWT、JWS、JWE、JWK和JWA RFC規(guī)范的Java實(shí)現(xiàn)。
這個(gè)庫(kù)是由Okta的Les Hazlewood創(chuàng)建的,現(xiàn)在由一個(gè)貢獻(xiàn)者社區(qū)維護(hù)。
什么是JSON Web Token
JWT是一種在兩方之間傳輸信息的方法。
在JWT的主體中編碼的信息被稱為claims。JWT的擴(kuò)展形式是JSON格式,因此每個(gè)claim都是JSON對(duì)象中的一個(gè)鍵。
JWTs可以加密簽名(使它成為JWS)或加密(使它成為JWE)。
這為JWTs增強(qiáng)了可驗(yàn)證性。例如,接收者可以確定JWT沒(méi)有通過(guò)驗(yàn)證簽名來(lái)篡改。
所生成JWT的結(jié)果是有三個(gè)部分的字符串,每個(gè)部分由"."分隔。
例如:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
每一節(jié)都是base 64編碼的。
第一部分是header,必須指定用于簽署JWT的算法。
eyJhbGciOiJIUzI1NiJ9
第二部分是body。本節(jié)包含了JWT編碼的所有聲明。
eyJzdWIiOiJKb2UifQ
最后一部分是signature。它通過(guò)在頭文件中指定的算法通過(guò)header和body的組合來(lái)計(jì)算。
ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
如果你通過(guò)一個(gè)基本的64解碼器傳遞前兩個(gè)部分,你將得到:
header
{
"alg": "HS256"
}
body
{
"sub": "Joe"
}
在這種情況下,我們得到的信息是使用sha - 256算法的HMAC來(lái)簽署JWT。而且,body有一個(gè)claim sub與value Joe。
Registered Claims 包含一些標(biāo)準(zhǔn)的claims,sub就是其中的一個(gè)(subject)。
要計(jì)算簽名,你必須知道簽名的sercrect。
安裝
Maven:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
Gradle:
dependencies {
compile 'io.jsonwebtoken:jjwt:0.9.0'
}
Note:JJWt依賴了 Jackson 2.x。
假如你依賴了jackson的老版本,你必須更新項(xiàng)目中的版本到新版本,否則會(huì)沖突。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.9</version>
</dependency>
快速使用
先看一個(gè)簡(jiǎn)單的例子:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.crypto.MacProvider;
import java.security.Key;
// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.
Key key = MacProvider.generateKey();
String compactJws = Jwts.builder()
.setSubject("Joe")
.signWith(SignatureAlgorithm.HS512, key)
.compact();
在上邊的例子中下,我們構(gòu)建了一個(gè)JWT,該JWT將將注冊(cè)的claim的sub(subject)設(shè)置為Joe,使用sha - 512算法在HMAC上注冊(cè)JWT。最后,我們將它轉(zhuǎn)換成字符串形式。
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJKb2UifQ.yiV1GWDrQyCeoOswYTf_xvlgsnaVVYJM0mU6rkmRBf2T1MBl3Xh2kZii0Q9BdX5-G0j25Qv2WF4lA6jPl5GKuA
下面來(lái)驗(yàn)證一下jwt:
assert Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws).getBody().getSubject().equals("Joe");
這里有兩個(gè)時(shí)間。之前的密鑰被用來(lái)驗(yàn)證JWT的簽名。如果未能驗(yàn)證JWT,則拋出一個(gè)簽名異常。假設(shè)JWT已被驗(yàn)證,我們將解析claim并斷言該sub被設(shè)置為Joe。
但如果簽名驗(yàn)證失敗了怎么辦?可以捕獲簽名異常并做出相應(yīng)的反應(yīng):
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws);
//OK, we can trust this JWT
} catch (SignatureException e) {
//don't trust the JWT!
}
支持的特性
兼容的規(guī)范
- 創(chuàng)建和解析明文壓縮JWTs
- 創(chuàng)建、解析和驗(yàn)證所有標(biāo)準(zhǔn)JWS算法的數(shù)字簽名JWTs(又稱JWSs):
- HS256: HMAC using SHA-256
- HS384: HMAC using SHA-384
- HS512: HMAC using SHA-512
- RS256: RSASSA-PKCS-v1_5 using SHA-256
- RS384: RSASSA-PKCS-v1_5 using SHA-384
- RS512: RSASSA-PKCS-v1_5 using SHA-512
- PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
- PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
- PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
- ES256: ECDSA using P-256 and SHA-256
- ES384: ECDSA using P-384 and SHA-384
- ES512: ECDSA using P-521 and SHA-512
增強(qiáng)的規(guī)范
- body壓縮。如果JWT體大,可以使用壓縮解碼器來(lái)壓縮它。最重要的是,JJWT庫(kù)將自動(dòng)解壓并解析JWT,而不需要額外的編碼。
String compactJws = Jwts.builder()
.setSubject("Joe")
.compressWith(CompressionCodecs.DEFLATE)
.signWith(SignatureAlgorithm.HS512, key)
.compact();
如果檢查Jws的header部分,它就會(huì)對(duì)這個(gè)進(jìn)行解碼:
{
"alg": "HS512",
"zip": "DEF"
}
JJWT自動(dòng)檢測(cè)到壓縮是通過(guò)檢查頭來(lái)使用的,并且在解析時(shí)將自動(dòng)解壓。對(duì)于解壓縮,不需要額外的編碼。
- 要求claims。在解析時(shí),您可以指定某些斷言必須存在并設(shè)置為某個(gè)值。
try {
Jws<Claims> claims = Jwts.parser()
.requireSubject("Joe")
.require("hasMotorcycle", true)
.setSigningKey(key)
.parseClaimsJws(compactJws);
} catch (MissingClaimException e) {
// we get here if the required claim is not present
} catch (IncorrectClaimException e) {
// we get here if the required claim has the wrong value
}
Registered Claim
所有的claim是可選的,并且是大小寫敏感的。
1. "iss" (Issuer) Claim
"iss" (issuer)是簽發(fā)該證書的負(fù)責(zé)人。
2. "sub" (Subject) Claim
"sub" (Subject)是主體。
3. "aud" (Audience) Claim
"aud" (Audience) Claim是指jwt的接受者,假如aud沒(méi)有發(fā)現(xiàn),則解析jwt時(shí)會(huì)拋出異常
4. "exp" (Expiration Time) Claim
"exp" (Expiration Time)指的是過(guò)期時(shí)間,假如超過(guò)過(guò)期時(shí)間,則會(huì)拋出異常
5. "nbf" (Not Before) Claim
"nbf" (Not Before) Claim指的是開(kāi)始日期,claim要求當(dāng)前日期/時(shí)間必須在以后或等于
在“nbf”聲明中列出的日期/時(shí)間
6. "iat" (Issued At) Claim
"iat" (Issued At) Claim是指jwt的發(fā)行時(shí)間
7. "jti" (JWT ID) Claim
"jti" (JWT ID) Claim為JWT提供了惟一的標(biāo)識(shí)符,如果應(yīng)用程序
使用多個(gè)發(fā)行者,必須在值之間避免沖突,
由不同的發(fā)行商制作。