JWT(JSON Web Tokens)入门与Java实践
一、JWT简介
随着现代Web应用的广泛应用,在保障系统的安全性方面扮演了核心要素的角色。JSON Web Tokens(JWT)作为官方规范(RFC 7519)所定义的技术标准,在各网络间提供了高效且封闭的方式来安全传递数据内容。通过提供一个可靠的身份验证与权限管理机制,JWT得以实现双方之间的安全通信与权限控制。
二、JWT的组成
JWT分为三个组成部分:Header、Payload和Signature;这三个组成部分之间以点号分隔开
通常**Header(头部)**部分包含两个关键信息:token type(令牌类型)和signature algorithm(签名算法),例如HMAC SHA256或RSA等常见算法。这些数据被以JSON格式存储,并通过Base64Url进行编码处理以确保传输的安全性和可读性。
示例:
{
"alg": "HS256",
"typ": "JWT"
}
- Payload(负载) 包括了一些声明(Claims),这些声明主要涉及实体(通常是用户)并伴随有额外的元数据。标准中明确定义了三种类型的声称:注册声称、公共声称以及私人声称。注册声称通常是一组预先定义好的常见声称,例如
iss(发证者)、exp(过期时间)等。此外,在这种情况下,“加载信息”也采用JSON格式,并经过Base64Url编码处理以确保安全传输。
示例:
{
"sub": "user123",
"admin": true,
"exp": 1516239022
}
- Signature(签名) :用于验证消息完整性的真实性部分被称为签名。它是由将Message分为两部分——即Header与Payload,并应用预定义算法以及密钥对这两部分进行处理后生成的结果所形成的字段。
该字段的存在有助于防止JWT在传输过程中被恶意篡改。
三、JWT的工作流程
系统要求用户输入用户名和密码以发起登录请求至服务器。
当服务器确认用户的账户信息无误时,在完成身份验证后会生成一个包含相应数据的JSON Web Token(JWT),并将此数据传递给客户端设备。
接收到来自服务端的JSON Web Token(JWT)后,在客户端设备上将其缓存至localStorage、cookie或其他临时存储区域以便后续处理。
每次发起网络请求时,在HTTP头中的Authorization字段内放置带有‘Bearer ’前缀的JSON Web Token(JWT)即可完成身份验证过程。
当服务端解析到带有Bearer授权头(Bearer Token)的身份认证头时,在解密并检查其有效性与完整性之后即可授权访问相关资源;若认证失败则返回相应的错误响应。
四、Java中使用JWT
在Java编程语言中提供了多个库以辅助处理JSON Web Token(JWT),其中较为常用的是库jjwt。以下提供了一个基本示例来说明如何使用这些库生成并验证JSON Web Token的基本流程。
- 添加依赖
第一步需要在项目依赖关系配置文件pom.xml中进行配置(如果你使用的是Maven):
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version> <!-- 请检查是否有更新的版本 -->
</dependency>
- 生成JWT
下面是一个简单的Java方法,用于生成JWT:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final String SECRET_KEY = "yourSecretKey"; // 密钥,应该保存在安全的地方,不要硬编码在代码中
private static final long EXPIRATION_TIME = 604800L; // 过期时间,这里设置为一周(单位为秒)
public static String createToken(String userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("user_id", userId);
return Jwts.builder()
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME * 1000))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}
- 验证JWT
验证JWT的方法如下所示:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.lang.reflect.Method;
public class JwtUtil {
// ... 其他方法 ...
public static void verifyToken(String token) throws Exception {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
// 可以从这里获取存储在JWT中的信息,如用户ID等
String userId = claims.get("user_id", String.class);
System.out.println("User ID from token: " + userId);
// 还可以检查token是否过期等其他验证逻辑...
}
}
在实际应用中,在遇到一些特殊情况下(如 token 过期、签名不匹配),可能会出现错误信息。\nJwts.parser().parseClaimsJws(token) 方法会在 token 失效或超时时触发异常。\n建议将验证逻辑放置于 try-catch 块内,并针对这些情况进行相应的处理。
五、安全性考虑
- 建议采用HTTPS协议传输JWT以防止中间人窃取或篡改敏感数据。
- 避免将敏感信息存储在JWT中尽管它们是可以被解码的。
- 合理设置JWT的有效期以确保旧token不会被长时间使用。
- 定期更新签名密钥以提升系统的安全性。
- 采用安全措施存储签名密钥避免将其嵌入代码或公开存储。
- 在服务器端验证JWT时确保其完整性有效性并妥善处理异常情况。
六、总结
