Java 中 JWT 相关知识全面解析与实战指南
一、什么是 JWT?
JWT(JSON Web Token)是一种基于 JSON 格式的令牌,用于在双方之间安全地传输信息。它主要应用于认证和授权场景,尤其在前后端分离项目中十分常见。
JWT 的结构
JWT 由三部分组成:
- Header(头部):描述 JWT 的元信息,比如签名算法。
- Payload(负载):存储用户的非敏感信息,如
userId
、username
。 - Signature(签名):用于验证数据完整性,确保令牌未被篡改。
一个 JWT 示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywidXNlcm5hbWUiOiJqb2huZG9lIiwiaWF0IjoxNjkwOTY3NjAwLCJleHAiOjE2OTA5NzEyMDB9.aWQl3zjW7dK3WY3xOt3MzIlQbK4XkwnAs8fN8LS9hEI
解码后的结构:
- Header:
{
"alg": "HS256",
"typ": "JWT"
}
- Payload:
{
"userId": 123,
"username": "johndoe",
"iat": 1690967600,
"exp": 1690971200
}
- Signature:
由头部和负载通过指定算法(如 HMAC SHA256)加密生成,用于验证数据完整性。
二、JWT 的核心特点
- 无状态性:无需服务器存储令牌状态信息,每次请求携带 JWT 即可验证用户身份。
- 安全性:使用签名机制验证令牌完整性,防止篡改。
- 便携性:基于 Base64 编码,便于传输。
三、JWT 的常见应用场景
- 用户登录认证:用户登录成功后,返回 JWT 令牌用于后续请求认证。
- 接口权限控制:基于 JWT 中的角色信息决定用户是否有权访问某些接口。
- 前后端分离项目:通过 HTTP Header 携带 JWT 进行身份验证,简化开发流程。
四、如何在 Java 中使用 JWT
以下内容基于 Spring Boot 框架,结合 jjwt 库(io.jsonwebtoken
),详细介绍 JWT 的生成、解析和验证。
1. 引入依赖
在 pom.xml
中添加 jjwt 依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- For JSON parsing -->
<version>0.11.5</version>
</dependency>
2. 配置 JWT 工具类
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final String SECRET_KEY = "mySecretKey"; // 签名密钥
private static final long EXPIRATION_TIME = 3600000; // 1 小时(单位:毫秒)
/**
* 生成 JWT Token
*
* @param claims 自定义的负载(如用户信息)
* @return JWT 字符串
*/
public static String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date()) // 签发时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 过期时间
.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // 签名算法
.compact();
}
/**
* 验证 Token 并解析
*
* @param token JWT 字符串
* @return 解析后的 Claims
*/
public static Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
/**
* 检查 Token 是否过期
*
* @param claims JWT 的 Claims
* @return 是否过期
*/
public static boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
3. 实际项目中的使用
用户登录认证
Controller 示例:
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(@RequestBody Map<String, String> loginData) {
String username = loginData.get("username");
String password = loginData.get("password");
// 模拟用户验证
if ("admin".equals(username) && "123456".equals(password)) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", username);
claims.put("role", "admin");
String token = JwtUtil.generateToken(claims);
Map<String, Object> response = new HashMap<>();
response.put("token", token);
return ResponseEntity.ok(response);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("message", "用户名或密码错误"));
}
}
}
接口权限验证
JWT 拦截器配置:
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
try {
token = token.replace("Bearer ", "");
Claims claims = JwtUtil.validateToken(token);
request.setAttribute("claims", claims);
return true;
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}
}
拦截器注册:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/auth/login"); // 排除登录接口
}
}
五、总结
通过本文,您了解了 JWT 的基本原理及其在 Java 项目中的实际应用,包括:
- JWT 的组成与特点。
- 使用 jjwt 库生成和验证 Token。
- 在实际项目中如何结合登录认证和权限控制。
JWT 是前后端分离项目中不可或缺的一部分,掌握它可以极大地提升开发效率。如果您有任何问题,欢迎在评论区留言讨论!
记得点赞、收藏 🎉