07.3 — 方法安全与 CSRF
定位: 方法级别的权限控制和 CSRF 防护机制 面试高频度: ⭐⭐⭐⭐ 考查方式: @PreAuthorize/@PostAuthorize 使用、CSRF 启用/禁用场景
一、这是什么?为什么需要它?
方法安全让权限控制从 Web 层深入到 Service 层,使用注解声明方法级别的访问规则。CSRF 防护防止跨站请求伪造攻击。
二、原理拆解
2.1 方法安全注解
java
@Configuration
@EnableMethodSecurity // Spring Security 6+(替代 @EnableGlobalMethodSecurity)
public class MethodSecurityConfig {}
@Service
public class DocumentService {
// 需要 ADMIN 角色
@PreAuthorize("hasRole('ADMIN')")
public void deleteAll() { ... }
// 基于 SpEL 的条件
@PreAuthorize("#document.owner == authentication.name")
public void updateDocument(Document document) { ... }
// 方法后校验
@PostAuthorize("returnObject.owner == authentication.name")
public Document findById(Long id) { ... }
// 过滤返回集合
@PostFilter("filterObject.visible == true")
public List<Document> findAll() { ... }
}注解对比
| 注解 | 功能 | 执行时机 |
|---|---|---|
| @PreAuthorize | 方法执行前权限校验 | 进入方法前 |
| @PostAuthorize | 方法执行后权限校验 | 返回后 |
| @PreFilter | 过滤输入集合 | 执行前 |
| @PostFilter | 过滤返回集合 | 执行后 |
2.2 CSRF 防护
客户端 -> GET /login -> 返回登录页 + CSRF Token
客户端 -> 提交表单 + CSRF Token -> POST /login
Spring Security -> 校验 Token -> 登录成功禁用 CSRF(无状态 API 场景)
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // 无状态 API 禁用 CSRF
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}注意:CSRF 对有状态会话(浏览器表单提交)是必须的,对无状态 API(JWT/Basic Auth)可以禁用。
三、面试视角
| 追问 | 答案要点 |
|---|---|
| @PreAuthorize 和 @Secured 区别? | @PreAuthorize 支持 SpEL(更灵活),@Secured 仅支持角色名 |
| CSRF 什么场景启用/禁用? | 有状态表单 -> 启用;无状态 JWT API -> 禁用 |
| @PostFilter 性能注意点? | 在内存中过滤,大数据量时注意性能 |
📚 相关链接
- **认证流程与过滤器链** — 过滤器链基础
- **JWT与OAuth2** — 无状态 JWT 方案
- ← 返回 **返回 Spring Security 索引**