跳到主要内容

Security 概述

Personal Blog Backend 使用 Spring Security 6 + JWT 实现无状态认证和授权。


🎯 架构概览

sequenceDiagram
participant C as 客户端
participant F as JWT 过滤器
participant S as SecurityContext

C->>F: 请求 + Authorization: Bearer {token}
F->>F: 验证 Token 签名
F->>F: 解析用户信息 (username, userId, roles)
F->>S: 设置认证上下文
S-->>C: 继续处理请求
无状态认证

所有用户信息存储在 JWT Token 中,无需查询数据库


🔧 三链架构

项目采用多过滤链设计,使用 @Order 控制优先级:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

// 链1: 白名单 (@Order(1)) - 公开端点
@Bean @Order(1)
public SecurityFilterChain permitAllChain(HttpSecurity http) { }

// 链2: JWT 认证 (@Order(2)) - API 端点
@Bean @Order(2)
public SecurityFilterChain jwtChain(HttpSecurity http) { }

// 链3: 默认认证 (@Order(3)) - 兜底策略
@Bean @Order(3)
public SecurityFilterChain defaultChain(HttpSecurity http) { }
}

请求匹配规则

匹配路径认证方式
permitAllChain白名单配置无需认证
jwtChain/api/**JWT Bearer Token
defaultChain其他所有HTTP Basic + Form

📋 白名单配置

application.yaml
app:
security:
permit-all-urls:
- /actuator/health
- /actuator/info
- /v3/api-docs/**
- /swagger-ui/**
jwt-secret: ${JWT_SECRET}
jwt-expiration: 7200000 # 2小时

API 端点权限

端点权限
/api/v1/auth/register公开
/api/v1/auth/login公开
/api/v1/**需要 JWT

🔐 方法级权限

使用 @PreAuthorize 注解控制方法权限:

// 需要认证
@GetMapping("/me")
public Result<UserVO> getCurrentUser() { }

// 需要 ADMIN 角色
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/{id}")
public Result<UserVO> getUserById(@PathVariable Long id) { }

// 多角色(OR)
@PreAuthorize("hasAnyRole('ADMIN', 'EDITOR')")
@PutMapping("/{id}")
public Result<Void> updateUser() { }

// 自定义表达式
@PreAuthorize("hasRole('ADMIN') or #id == principal.userId")
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Long id) { }

🛠️ 核心组件

组件位置职责
SecurityConfigblog-application三链配置
JwtTokenProviderblog-commonToken 生成/验证
JwtAuthenticationFilterblog-application请求过滤器
SecurityUtilsblog-common获取当前用户
SecurityPropertiesblog-common配置属性绑定

📚 延伸阅读