JWT Token 介绍
1. 什么是 JWT Token?
JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。每个Token都是经过签名的,因此你可以验证发送者的身份并确保数据未被篡改。
2. JWT Token 的结构
一个JWT通常包含三部分:Header(头部)、Payload(负载)和Signature(签名)。
-
Header:通常包含两部分:令牌的类型(即JWT)和所使用的签名算法,如HMAC SHA256或RSA。
-
Payload:包含声明(claims)。声明有三种类型:注册的声明、公共的声明和私有的声明。
- 注册的声明:一组预定义的声明,它们不是强制性的,但推荐使用,如iss(issuer,签发人)、exp(expiration time,过期时间)、sub(subject,主题)等。
- 公共的声明:可以添加任何信息,但要避免添加敏感信息,因为它们可以被解码(尽管不能被篡改)。
- 私有的声明:用于在信息的发送方和接收方之间共享信息,不应该包含敏感信息。
-
Signature:用于验证消息在传输过程中没有被更改,并且,对于使用私钥签名的Token,还可以验证发送者的身份。
3. JWT Token 的工作流程
- 用户使用用户名和密码登录应用。
- 应用验证用户的凭据。
- 一旦验证通过,应用会创建一个包含用户信息和其他必要声明的JWT,并使用一个秘钥进行签名。
- 应用将这个JWT返回给用户。
- 用户在随后的每个请求中将JWT发送回服务器,通常是在HTTP请求的Authorization头部中。
- 服务器通过验证JWT的签名来确认它是由服务器签发的,并且没有被篡改。
- 如果验证通过,服务器处理请求。
4. 为什么使用 JWT Token?
- 无状态和可扩展性:由于JWT包含所有必要的信息,服务器不需要保存用户状态,这使得JWT非常适合分布式系统和可扩展的Web应用。
- 安全:JWT可以通过使用强签名算法来保证数据的完整性和验证发送者的身份。
- 自包含:JWT包含了所有用户验证所需的信息,减少了需要查询数据库的次数。
5. 常用的 Java 解析工具类
在Java中,有多个库可以用来创建和解析JWT,以下是一些常用的库:
-
jjwt:由Netflix开发的一个轻量级库,用于创建和解析JWT。
Maven依赖:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
-
auth0/java-jwt:Auth0提供的JWT库,支持JWT的创建和解析。
Maven依赖:
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.1</version> </dependency>
-
java-jwt:一个简单易用的JWT库,用于创建和解析JWT。
Maven依赖:
<dependency> <groupId>com.github.kevinsawicki</groupId> <artifactId>http-request</artifactId> <version>6.0</version> </dependency>
6. 示例代码
以下是使用jjwt库解析JWT的简单示例:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtExample {
public static void main(String[] args) {
// 示例JWT字符串
String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UiLCJleHAiOjE2MTYyMzkwMjJ9.HSMxgZzouqL1tT4";
// 解析JWT
Jws<Claims> jws = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(jwt);
// 获取Claims
Claims claims = jws.getBody();
System.out.println("Subject: " + claims.getSubject());
System.out.println("Expiration: " + claims.getExpiration());
}
}
请注意,实际使用中,你需要根据你的应用需求选择合适的库,并妥善保管用于签名的秘钥。