在 Spring 应用中,使用 JSON Web Token (JWT) 是一种常见的认证和授权机制。JWT 是一种基于 JSON 的开放标准 (RFC 7519),用来在各方之间传递安全、可信的数据。以下是如何在 Spring 框架中集成和使用 JWT 的完整指南。
核心概念
-
JWT 结构:
- Header:包含类型和签名算法信息。
- Payload:包含声明 (claims),如用户信息、角色等。
- Signature:用来验证 token 的完整性,通常使用 HMAC 或 RSA 等算法。
-
使用场景:
JWT 的使用通常分为以下几个步骤:
- 用户通过用户名和密码登录,后端验证用户身份。
- 后端生成 JWT(包含用户的相关信息),并将其返回给前端。
- 前端存储该 JWT(一般存储在 LocalStorage 或 Cookie 中)。
- 后续每次请求,前端都会将该 JWT 放入请求头的
Authorization
字段中,后端验证 JWT 的合法性。 - 后端根据 JWT 中的内容进行相应的认证和授权。
集成步骤
以下是 Spring Boot 项目中使用 JWT 的主要步骤:
1. 添加依赖
在 pom.xml
中添加 JWT 相关依赖:
<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><version>0.11.5</version>
</dependency>
1. 创建 JWT 工具类
java">import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class JwtUtil {private static final String SECRET_KEY = "your_secret_key"; // 密钥// 生成安全密钥private final static SecretKey secretKey =Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET_KEY));// 过期时间(单位:毫秒)private static final long EXPIRATION = 3600000; // 一小时// 生成JWTpublic static String generateToken(String username, Integer id) {Map<String, Object> claims = new HashMap<>();claims.put("username", username); // 可以根据需要加入更多的自定义字段claims.put("userId", id);return Jwts.builder().setClaims(claims).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 过期时间1小时.signWith(secretKey) // 签名.compact();}// 解析JWTpublic static Claims parseToken(String token) throws JwtException {try {JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(secretKey);return jwtParserBuilder.build().parseClaimsJws(token).getBody();} catch (JwtException e) {// 捕获解析异常,抛出一个自定义的异常或返回nullthrow new JwtException("Invalid token: " + e.getMessage(), e);}}// 检查JWT是否有效public static boolean isTokenExpired(String token) {try {Claims claims = parseToken(token);return claims.getExpiration().before(new Date());} catch (JwtException e) {// 解析失败,视为Token无效return true;}}// 获取用户名public static String getUsername(String token) {try {Claims claims = parseToken(token);return claims != null ? claims.get("username", String.class) : null;} catch (JwtException e) {// Token无效,返回null或可以选择抛出异常return null;}}// 获取用户idpublic static Integer getUserId(String token) {try {Claims claims = parseToken(token);return claims != null ? claims.get("userId", Integer.class) : null;} catch (JwtException e) {// Token无效,返回null或可以选择抛出异常return null;}}
}
2. 创建 JWT 拦截器
接下来,创建一个 HandlerInterceptor
实现 JWT 登录验证逻辑。这个拦截器会在每次请求时验证请求头中的 JWT 是否有效。
java">import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class JwtInterceptor implements HandlerInterceptor {@Overridepublic 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);response.getWriter().write("Unauthorized: No token provided");return false;}token = token.substring(7); // 去掉 "Bearer " 前缀if (JwtUtil.isTokenExpired(token)) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("Unauthorized: Token expired");return false;}String username = JwtUtil.getUsername(token);if (username == null) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("Unauthorized: Invalid token");return false;}// 将用户名或用户信息放入请求属性中,后续处理可以使用request.setAttribute("username", username);return true; // 继续执行请求}
}
3. 配置拦截器
在 WebMvcConfigurer
中注册该拦截器,使其在处理请求之前执行。
java">import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**") // 所有路径都需要拦截.excludePathPatterns("/login", "/register"); // 排除登录和注册等不需要JWT验证的路径}
}
4. 创建登录接口
最后,创建一个登录接口用于用户认证,验证成功后生成 JWT 并返回给前端。
java">import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AuthController {@PostMapping("/login")public String login(@RequestParam String username, @RequestParam String password) {// 在这里根据实际情况验证用户名和密码if ("user".equals(username) && "password".equals(password)) {// 生成 JWTString token = JwtUtil.generateToken(username);return "Bearer " + token; // 返回JWT}return "Invalid credentials"; // 登录失败}
}
总结
- 创建了一个
JwtUtil
工具类,用于生成、解析和验证 JWT。 - 创建了一个
JwtInterceptor
拦截器,在每次请求时验证 JWT 的有效性。 - 使用
WebMvcConfigurer
配置了该拦截器,并指定哪些路径需要拦截。 - 创建了一个登录接口,用户登录时通过用户名和密码获取 JWT。
通过这些步骤,你就可以使用 JWT 实现一个基本的登录验证功能,并且在 Spring 应用中通过拦截器进行保护,确保请求中的 JWT 合法且有效。