关于 spring-boot-security-jwt
面向 Spring Boot 开发者的 JWT 安全实现技能,提供无状态认证、令牌轮换及细粒度授权模式。内容针对 Spring Security 6.x 和 JJWT。
主要功能
- 01访问令牌与刷新令牌生成和验证
- 02Bearer 与 HttpOnly Cookie 认证
- 03刷新令牌轮换、撤销与黑名单
- 04基于角色和权限的授权规则
- 05OAuth2 集成与安全测试
适用场景
- 01为 REST API 添加 JWT 认证
- 02实现登录、刷新和注销流程
- 03配置基于角色或权限的访问控制
- 04测试 Spring Security 配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill spring-boot-security-jwt安装后在 Claude Code 中输入/spring-boot-security-jwt确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/generate-jwt-keys.shreferences/authorization-patterns.mdconfiguration.mdexamples.mdjwt-complete-configuration.mdjwt-configuration.mdjwt-quick-reference.mdjwt-testing-guide.mdmicroservices-security.mdmigration-spring-security-6x.mdoauth2-integration.mdperformance-optimization.mdsecurity-hardening.mdstructure.mdtesting-jwt-security.mdtesting.mdtoken-management.mdtroubleshooting.mdscripts/test-jwt-setup.sh详细介绍
Spring Boot JWT 安全
适用于 Spring Boot 3.5.x、Spring Security 6.x 和 JJWT 的 JWT 身份验证与授权模式。涵盖令牌生成、验证、刷新策略、RBAC/ABAC 和 OAuth2 集成。
概述
此技能提供在 Spring Boot 应用中实现无状态 JWT 身份验证的模式。涵盖完整的身份验证流程,包括使用 JJWT 0.12.6 生成令牌、基于 Bearer/ Cookie 的身份验证、刷新令牌轮换,以及使用 @PreAuthorize 表达式进行方法级授权。
主要功能:
- 生成具有可配置过期时间的访问令牌和刷新令牌
- Bearer 令牌和 HttpOnly Cookie 身份验证策略
- 与 Spring Data JPA 和 OAuth2 提供方集成
- 基于角色/权限的 RBAC
@PreAuthorize规则 - 用于注销/轮换的令牌撤销和黑名单
适用场景
在用户提出以下请求时启用:
- “实现 JWT 身份验证”“使用令牌保护 REST API”
- “Spring Security 6.x 配置”“设置 SecurityFilterChain”
- “基于角色的访问控制”“RBAC”“
`@PreAuthorize`” - “刷新令牌”“令牌轮换”“令牌撤销”
- “OAuth2 集成”“社交登录”“Google/GitHub 身份验证”
- “无状态身份验证”“SPA 后端安全”
- “JWT 过滤器”“OncePerRequestFilter”“Bearer 令牌”
- “基于 Cookie 的 JWT”“HttpOnly Cookie”
- “基于权限的访问控制”“自定义 PermissionEvaluator”
快速参考
依赖项(JJWT 0.12.6)
| 构件 | 作用域 |
|---|---|
spring-boot-starter-security | compile |
spring-boot-starter-oauth2-resource-server | compile |
io.jsonwebtoken:jjwt-api:0.12.6 | compile |
io.jsonwebtoken:jjwt-impl:0.12.6 | runtime |
io.jsonwebtoken:jjwt-jackson:0.12.6 | runtime |
spring-security-test | test |
Maven 和 Gradle 代码片段请参阅 references/jwt-quick-reference.md。
关键配置属性
| 属性 | 示例值 | 说明 |
|---|---|---|
jwt.secret | ${JWT_SECRET} | 至少 256 位,切勿硬编码 |
jwt.access-token-expiration | 900000 | 15 分钟,单位为毫秒 |
jwt.refresh-token-expiration | 604800000 | 7 天,单位为毫秒 |
jwt.issuer | my-app | 每次都验证 |
jwt.cookie-name | jwt-token | 用于基于 Cookie 的身份验证 |
jwt.cookie-http-only | true | 生产环境中始终设为 true |
jwt.cookie-secure | true | 使用 HTTPS 时始终设为 true |
授权注解
| 注解 | 示例 |
|---|---|
@PreAuthorize("hasRole('ADMIN')") | 角色检查 |
@PreAuthorize("hasAuthority('USER_READ')") | 权限检查 |
@PreAuthorize("hasPermission(#id, 'Doc', 'READ')") | 领域对象检查 |
@PreAuthorize("@myService.canAccess(#id)") | Spring Bean 检查 |
操作说明
步骤 1 — 添加依赖项
在构建文件中加入 spring-boot-starter-security、spring-boot-starter-oauth2-resource-server 和三个 JJWT 构件。准确的 Maven/Gradle 代码片段请参阅 references/jwt-quick-reference.md。
步骤 2 — 配置 application.yml
jwt:
secret: ${JWT_SECRET:change-me-min-32-chars-in-production}
access-token-expiration: 900000
refresh-token-expiration: 604800000
issuer: my-app
cookie-name: jwt-token
cookie-http-only: true
cookie-secure: false # true in production
完整属性参考请参阅 references/jwt-complete-configuration.md。
步骤 3 — 实现 JwtService
核心操作:生成访问令牌、生成刷新令牌、提取用户名、验证令牌。
@Service
public class JwtService {
public String generateAccessToken(UserDetails userDetails) {
return Jwts.builder()
.subject(userDetails.getUsername())
.issuer(issuer)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + accessTokenExpiration))
.claim("authorities", getAuthorities(userDetails))
.signWith(getSigningKey())
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
try {
String username = extractUsername(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
} catch (JwtException e) {
return false;
}
}
}
包含密钥管理和声明提取的完整 JwtService 请参阅 references/jwt-complete-configuration.md。
步骤 4 — 创建 JwtAuthenticationFilter
扩展 OncePerRequestFilter,从 Authorization: Bearer 标头(或 HttpOnly Cookie)中提取 JWT,验证令牌,并设置 SecurityContext。
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
String jwt = authHeader.substring(7);
String username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}
基于 Cookie 的实现变体请参阅 references/configuration.md。
步骤 5 — 配置 SecurityFilterChain
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/swagger-ui/**").permitAll()
.anyRequest().authenticated()
)
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
有关 CORS、注销处理器和 OAuth2 登录集成,请参阅 references/jwt-complete-configuration.md。
步骤 6 — 创建身份验证端点
通过 @RestController 暴露 /register、/authenticate、/refresh 和 /logout。在响应正文中返回 accessToken + refreshToken(也可以选择设置 HttpOnly Cookie)。
有关完整的 AuthenticationController 和 AuthenticationService,请参阅 references/examples.md。
步骤 7 — 实现刷新令牌策略
在数据库中存储刷新令牌,并使用 user_id、expiry_date、revoked 和 expired 列。在 /refresh 时,验证已存储的令牌,撤销该令牌,并签发一对新令牌(令牌轮换)。
有关 RefreshToken 实体、轮换逻辑和基于 Redis 的黑名单,请参阅 references/token-management.md。
步骤 8 — 添加授权规则
使用 @EnableMethodSecurity 和 @PreAuthorize 注解进行细粒度控制:
@PreAuthorize("hasRole('ADMIN')")
public Page<UserResponse> getAllUsers(Pageable pageable) { ... }
@PreAuthorize("hasPermission(#documentId, 'Document', 'READ')")
public Document getDocument(Long documentId) { ... }
有关 RBAC 实体模型、PermissionEvaluator 和 ABAC 模式,请参阅 references/authorization-patterns.md。
步骤 9 — 编写安全测试
@SpringBootTest
@AutoConfigureMockMvc
class AuthControllerTest {
@Test
void shouldDenyAccessWithoutToken() throws Exception {
mockMvc.perform(get("/api/orders"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAccess() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isOk());
}
}
有关完整测试套件、Testcontainers 配置和安全测试清单,请参阅 references/testing.md 和 references/jwt-testing-guide.md。
最佳实践
令牌安全
- 使用至少 256 位的密钥——从环境变量加载,切勿硬编码
- 设置较短的访问令牌有效期(15 min);使用刷新令牌延长会话
- 实现令牌轮换:签发新刷新令牌时撤销旧令牌
- 使用
jti(JWT ID)声明,在注销时将令牌加入黑名单
Cookie 与 Bearer 标头
- 对浏览器客户端优先使用 HttpOnly Cookie(可防范 XSS)
- 对移动端/API 客户端使用
Authorization: Bearer标头 - 在生产环境中为 Cookie 设置
Secure、SameSite=Lax或Strict
Spring Security 6.x
- 使用
SecurityFilterChainBean——切勿扩展WebSecurityConfigurerAdapter - 仅对无状态 API 禁用 CSRF;基于会话的流程应保持启用
- 使用
@EnableMethodSecurity,而非已弃用的@EnableGlobalMethodSecurity - 验证
iss和aud声明;拒绝来自不受信任发行者的令牌
性能
- 使用
@Cacheable缓存UserDetails,避免每次请求都查询数据库 - 缓存签名密钥的派生结果(避免每次请求都重新计算 HMAC 密钥)
- 大规模部署时使用 Redis 存储刷新令牌
不要做的事
- 不要在 JWT 声明中存储敏感数据(密码、个人身份信息)——声明仅经过签名,并未加密
- 不要签发有效期无限的令牌
- 不要接受未经签名和有效期验证的令牌
- 不要在不同环境之间共享签名密钥
示例
基本身份验证流程
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/authenticate")
public ResponseEntity<AuthResponse> authenticate(
@RequestBody LoginRequest request) {
return ResponseEntity.ok(authService.authenticate(request));
}
@PostMapping("/refresh")
public ResponseEntity<AuthResponse> refresh(@RequestBody RefreshRequest request) {
return ResponseEntity.ok(authService.refreshToken(request.refreshToken()));
}
@PostMapping("/logout")
public ResponseEntity<Void> logout() {
authService.logout();
return ResponseEntity.ok().build();
}
}
控制器方法中的 JWT 授权
@RestController
@RequestMapping("/api/admin")
@PreAuthorize("hasRole('ADMIN')")
public class AdminController {
@GetMapping("/users")
public ResponseEntity<List<UserResponse>> getAllUsers() {
return ResponseEntity.ok(adminService.getAllUsers());
}
}
有关完整的实体模型和服务实现,请参阅 references/examples.md。
参考资料
| 文件 | 内容 |
|---|---|
| references/jwt-quick-reference.md | 依赖、最简服务、常见模式 |
| references/jwt-complete-configuration.md | 完整配置:属性、SecurityFilterChain、JwtService、OAuth2 RS |
| references/configuration.md | JWT 配置 Bean、CORS、CSRF、错误处理、会话选项 |
| references/examples.md | 完整应用设置:控制器、服务、实体 |
| references/authorization-patterns.md | RBAC/ABAC 实体模型、PermissionEvaluator、SpEL 表达式 |
| references/token-management.md | 刷新令牌实体、轮换、使用 Redis 实现黑名单 |
| references/testing.md | 单元测试和 MockMvc 测试、测试工具 |
| references/jwt-testing-guide.md | Testcontainers、负载测试、安全测试清单 |
| references/security-hardening.md | 安全头、HSTS、速率限制、审计日志 |
| references/performance-optimization.md | Caffeine 缓存配置、异步验证、连接池 |
| references/oauth2-integration.md | Google/GitHub OAuth2 登录、OAuth2UserService |
| references/microservices-security.md | 服务间 JWT 传递、资源服务配置 |
| references/migration-spring-security-6x.md | 从 Spring Security 5.x 迁移 |
| references/troubleshooting.md | 常见错误、调试技巧 |
限制和警告
安全限制
- JWT 令牌经过签名但未加密 — 不要在声明中包含敏感数据
- 在信任令牌之前,务必验证
exp、iss和aud声明 - 签名密钥必须至少为 256 位;生产环境中绝不能使用弱密钥
- 从环境变量或安全保管库加载密钥,绝不要从配置文件加载
- 基于 Cookie 的流程必须设置 SameSite Cookie 属性以防范 CSRF
Spring Security 6.x 限制
WebSecurityConfigurerAdapter已移除 — 只能使用SecurityFilterChainBean@EnableGlobalMethodSecurity已弃用 — 使用@EnableMethodSecurity- 配置
HttpSecurity时必须使用 Lambda DSL(不能使用方法链式调用) WebSecurityConfigurerAdapter.order()已由@Configuration类上的@Order取代
令牌限制
- 出于安全考虑,访问令牌的有效期应为 5-15 分钟
- 刷新令牌应存储在服务端(数据库或 Redis),绝不能存储在 localStorage 中
- 实现令牌黑名单,以便在注销时立即撤销令牌
- 正确实现令牌黑名单需要
jti声明
相关技能
spring-boot-dependency-injection— 全文使用的构造函数注入模式spring-boot-rest-api-standards— REST API 安全模式和错误处理unit-test-security-authorization— Spring Security 配置测试spring-data-jpa— 用户实体和仓库模式spring-boot-actuator— 安全监控和健康检查端点