JWT 简介
JSON Web Tokens 是一种开放标准(RFC 7519),用于在网络应用环境间传递声明。这些声明通常包含用户身份验证和授权信息。JWT被设计为紧凑且安全的,尤其适用于分布式站点的单点登录(SSO)场景。
JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三部分通过点号(.)连接成一个字符串。
-
头部(Header):描述JWT的元数据,例如签名算法。头部是一个JSON对象,通常包含以下字段:
typ
:表示JWT的类型,通常是"JWT"。alg
:表示用于签名的算法,如HMAC SHA256。
-
载荷(Payload):包含实际需要传递的数据,如用户身份信息。载荷也是一个JSON对象,其中包含了官方定义的声明字段,如
iss
(签发者)、sub
(所面向的用户)、aud
(接收方)等,以及任何自定义的私有声明。 -
签名(Signature):用于验证JWT的完整性和真实性。签名是通过使用Header中指定的算法(如HMAC SHA256)生成的。
JWT的优点包括:
-
无状态:JWT自身包含了所有必要的信息,不需要服务器存储任何会话信息,这增加了系统的可用性和可伸缩性。
-
安全性:JWT设计为紧凑且安全,难以被篡改。
-
易于集成:JWT可以轻松地与各种编程语言和框架集成。
但JWT也有其缺点,如不可控性,一旦生成了JWT,就无法对其进行修改或使其失效,只能等待过期。
JWT的使用流程通常如下:
- 用户请求登录,并提供用户名和密码。
- 服务器验证用户信息,并生成一个JWT。
- 服务器将JWT返回给用户。
- 用户在每次请求时携带JWT,服务器验证JWT的有效性,并据此处理请求。
CustomJWT 项目
这个项目其实官方就已经为大家提供了相关的Java JWT接口,但是不怎么好用(对于我来说,不够明确),为了解决这个问题,我在这里使用 Java 创建了 JWT 的用例,让更多人能够更快且简单的用上这个 JWT,目前也已经开源到 CustomJWT 上,在 Maven 中央库都已经上传了这个相关项目:
Java Maven 调用本次项目的库:
<dependency>
<groupId>top.pulselink.java</groupId>
<artifactId>customjwt</artifactId>
<version>1.0.0</version>
</dependency>
Java Gradle 调用本次项目的库:
implementation group: 'top.pulselink.java', name: 'customjwt', version: '1.0.0'
这个项目从根本上解决了难用的问题,且支持下面的算法:
JWS | Algorithm | Description |
---|---|---|
HS256 | HMAC256 | HMAC with SHA-256 |
HS384 | HMAC384 | HMAC with SHA-384 |
HS512 | HMAC512 | HMAC with SHA-512 |
PS256 | RSA256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 |
PS384 | RSA384 | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 |
PS512 | RSA512 | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 |
RS256 | RSA256 | RSASSA-PKCS1-v1_5 with SHA-256 |
RS384 | RSA384 | RSASSA-PKCS1-v1_5 with SHA-384 |
RS512 | RSA512 | RSASSA-PKCS1-v1_5 with SHA-512 |
ES256 | ECDSA256 | ECDSA with curve P-256 and SHA-256 |
ES384 | ECDSA384 | ECDSA with curve P-384 and SHA-384 |
ES512 | ECDSA512 | ECDSA with curve P-521 and SHA-512 |
下面的示例展示基本的 HS256 签名算法:
1. HS256 签名算法:
public static void main(String [] args){
try{
CustomJWT jwt = new CustomJWT(); //初始实例化
/*
准备Header
*/
String alg = "HS256"; //添加 Header
String type = "JWT"; //添加Header
String header = jwt.Header(alg, type); //给 header 添加进这两个元素
/*
准备Payload
*/
String[] payloadMessage = {
"sub", "1234567890", //1
"name", "John Doe", //2
"admin", "true", //3
"iat", Long.toString(1516239022L) //4
}; //准备好将 payload 的消息
/*
以下的isNumArray 这里的 `true` 是将 payload 里面的 `boolean` 类型和长整型生成对应的类型,
比如在 payload 里面的 `1` 这一行的注释输出的希望得到的是字符串类型,则直接输出 `false`,如果要输出为整数类型,则修改为 `true` 就行
比如这里的 `"admin", "true"`这里是将字符串来的 `true` 转变成 `boolean` 的类型.
显示将不带引号,同样的长整数类型同样也是这个道理,输出不为字符串类型
*/
boolean[] isNumArray = {false, false, true, true};
String payload = jwt.Payload(isNumArray, payloadMessage); //将消息添加到 Payload 部分
/*
准备Sign
*/
String key = "your-256-bit-secret"; //给下面的签名部分添加 secret
String sign = jwt.Signature(alg, header + "." + payload, key); //准备给 header 和 payload 生成签名
System.out.println(header + "." + payload + "." + sign); // JWT 生成,输出 Token
System.out.println(jwt.verifyHS(header + "." + payload + "." + sign, alg, key)); //输出 HS256 JWT 的验证,如果验证正确则输出true,否则输出false
}catch(Exception ex){
ex.printStackTrace();
}
}
上面的这个用例是最常见的(HS256)。其他更详细的内容可以访问 CustomJWT 获取。例如 PS256,RS256,ES256等