安全
Spring Security 是 Spring Boot 默认的安全框架,提供认证(Authentication)与授权(Authorization)能力。引入 spring-boot-starter-security 后自动生效。
核心概念
请求
│
▼
Filter Chain(安全过滤器链)
├─ SecurityContextPersistenceFilter # 从 Session/Token 恢复上下文
├─ UsernamePasswordAuthenticationFilter # 表单登录
├─ BearerTokenAuthenticationFilter # JWT / OAuth2 Token
├─ ExceptionTranslationFilter # 统一处理 401/403
└─ FilterSecurityInterceptor # 授权决策
│
▼
Controller / 业务逻辑
| 概念 | 说明 |
|---|---|
Authentication | 当前登录用户信息(Principal + 权限列表) |
SecurityContext | 存放当前请求的 Authentication,线程本地 |
UserDetails | 用户详情接口(用户名、密码、权限、账号状态) |
GrantedAuthority | 权限/角色(如 ROLE_ADMIN) |
AuthenticationManager | 认证入口,委托给 AuthenticationProvider |
基本配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // REST API 通常禁用
.sessionManagement(s -> s
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // JWT 场景无状态
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll() // 公开接口
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 详见:密码加密
}
@Bean
public AuthenticationManager authManager(AuthenticationConfiguration config)
throws Exception {
return config.getAuthenticationManager();
}
}自定义用户服务
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepo.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword()) // 已加密的密码
.roles(user.getRoles().toArray(String[]::new))
.accountExpired(!user.isActive())
.build();
}
}JWT 认证流程
登录请求 POST /api/auth/login
│ username + password
▼
AuthenticationManager.authenticate()
│ 验证通过
▼
生成 JWT Token(accessToken + refreshToken)
│
▼
客户端请求携带 Header: Authorization: Bearer <token>
│
▼
JwtAuthFilter 解析 Token → 写入 SecurityContext
│
▼
Controller 正常处理
JWT 集成详见 OAuth2 与 JWT。
获取当前用户
// 方式一:SecurityContextHolder
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
// 方式二:Controller 参数注入(推荐)
@GetMapping("/me")
public UserInfo me(@AuthenticationPrincipal UserDetails user) {
return userService.findByUsername(user.getUsername());
}
// 方式三:自定义注解封装(常见于大型项目)
@GetMapping("/me")
public UserInfo me(@CurrentUser LoginUser user) { ... }授权
URL 级授权
在 SecurityFilterChain 中配置(见基本配置),常用表达式:
| 表达式 | 说明 |
|---|---|
permitAll() | 完全公开 |
authenticated() | 已登录即可 |
hasRole("ADMIN") | 拥有 ROLE_ADMIN 权限 |
hasAnyRole("ADMIN","USER") | 拥有任意一个角色 |
hasAuthority("user:delete") | 精确权限字符串 |
denyAll() | 完全禁止 |
方法级授权
详见 方法级安全。
@EnableMethodSecurity // 启用方法级安全(配置类上)
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }
@PreAuthorize("hasAuthority('order:read') or #userId == authentication.principal.id")
public Order getOrder(Long userId, Long orderId) { ... }
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) { ... }CSRF
REST API(前后端分离 + 无状态)通常禁用 CSRF:
http.csrf(csrf -> csrf.disable());传统 MVC(Session + 表单)需保留 CSRF,Thymeleaf 会自动注入 Token,详见 Thymeleaf。
异常处理
http.exceptionHandling(ex -> ex
.authenticationEntryPoint((req, res, e) -> {
// 401 未认证
res.sendError(HttpServletResponse.SC_UNAUTHORIZED, "请先登录");
})
.accessDeniedHandler((req, res, e) -> {
// 403 无权限
res.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
})
);可配合 全局异常处理 统一返回 JSON 格式错误响应。
相关链接
- OAuth2 与 JWT — Token 生成、刷新、解析
- 方法级安全 —
@PreAuthorize/@PostAuthorize - 密码加密 — BCrypt、加盐策略
- Session 管理 — 有状态认证场景
- 过滤器与拦截器 — 自定义过滤器接入安全链
- 全局异常处理 — 统一 401/403 响应格式