Java JWT: JSON Web Token for Java and Android
JJWT的是在JVM上创建和验证JSON Web Token(JWTs)的库。
JJWT是基于JWT、JWS、JWE、JWK和JWA RFC规范的Java实现。
这个库是由Okta的Les Hazlewood创建的,现在由一个贡献者社区维护。
什么是JSON Web Token
JWT是一种在两方之间传输信息的方法。
在JWT的主体中编码的信息被称为claims。JWT的扩展形式是JSON格式,因此每个claim都是JSON对象中的一个键。
JWTs可以加密签名(使它成为JWS)或加密(使它成为JWE)。
这为JWTs增强了可验证性。例如,接收者可以确定JWT没有通过验证签名来篡改。
所生成JWT的结果是有三个部分的字符串,每个部分由"."分隔。
例如:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
每一节都是base 64编码的。
第一部分是header,必须指定用于签署JWT的算法。
eyJhbGciOiJIUzI1NiJ9
第二部分是body。本节包含了JWT编码的所有声明。
eyJzdWIiOiJKb2UifQ
最后一部分是signature。它通过在头文件中指定的算法通过header和body的组合来计算。
ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
如果你通过一个基本的64解码器传递前两个部分,你将得到:
header
{
"alg": "HS256"
}
body
{
"sub": "Joe"
}
在这种情况下,我们得到的信息是使用sha - 256算法的HMAC来签署JWT。而且,body有一个claim sub与value Joe。
Registered Claims 包含一些标准的claims,sub就是其中的一个(subject)。
要计算签名,你必须知道签名的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的老版本,你必须更新项目中的版本到新版本,否则会冲突。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.9</version>
</dependency>
快速使用
先看一个简单的例子:
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();
在上边的例子中下,我们构建了一个JWT,该JWT将将注册的claim的sub(subject)设置为Joe,使用sha - 512算法在HMAC上注册JWT。最后,我们将它转换成字符串形式。
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJKb2UifQ.yiV1GWDrQyCeoOswYTf_xvlgsnaVVYJM0mU6rkmRBf2T1MBl3Xh2kZii0Q9BdX5-G0j25Qv2WF4lA6jPl5GKuA
下面来验证一下jwt:
assert Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws).getBody().getSubject().equals("Joe");
这里有两个时间。之前的密钥被用来验证JWT的签名。如果未能验证JWT,则抛出一个签名异常。假设JWT已被验证,我们将解析claim并断言该sub被设置为Joe。
但如果签名验证失败了怎么办?可以捕获签名异常并做出相应的反应:
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws);
//OK, we can trust this JWT
} catch (SignatureException e) {
//don't trust the JWT!
}
支持的特性
兼容的规范
- 创建和解析明文压缩JWTs
- 创建、解析和验证所有标准JWS算法的数字签名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
增强的规范
- body压缩。如果JWT体大,可以使用压缩解码器来压缩它。最重要的是,JJWT库将自动解压并解析JWT,而不需要额外的编码。
String compactJws = Jwts.builder()
.setSubject("Joe")
.compressWith(CompressionCodecs.DEFLATE)
.signWith(SignatureAlgorithm.HS512, key)
.compact();
如果检查Jws的header部分,它就会对这个进行解码:
{
"alg": "HS512",
"zip": "DEF"
}
JJWT自动检测到压缩是通过检查头来使用的,并且在解析时将自动解压。对于解压缩,不需要额外的编码。
- 要求claims。在解析时,您可以指定某些断言必须存在并设置为某个值。
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)是签发该证书的负责人。
2. "sub" (Subject) Claim
"sub" (Subject)是主体。
3. "aud" (Audience) Claim
"aud" (Audience) Claim是指jwt的接受者,假如aud没有发现,则解析jwt时会抛出异常
4. "exp" (Expiration Time) Claim
"exp" (Expiration Time)指的是过期时间,假如超过过期时间,则会抛出异常
5. "nbf" (Not Before) Claim
"nbf" (Not Before) Claim指的是开始日期,claim要求当前日期/时间必须在以后或等于
在“nbf”声明中列出的日期/时间
6. "iat" (Issued At) Claim
"iat" (Issued At) Claim是指jwt的发行时间
7. "jti" (JWT ID) Claim
"jti" (JWT ID) Claim为JWT提供了惟一的标识符,如果应用程序
使用多个发行者,必须在值之间避免冲突,
由不同的发行商制作。