1. Spring Security 6.x配置完全指南
最近在升级公司项目的安全框架时,我花了整整两周时间研究Spring Security 6.x的新特性。这个版本在配置方式上做了大量改进,特别是废弃了WebSecurityConfigurerAdapter这个经典基类,让不少老司机都踩了坑。今天我就把这次升级过程中的关键配置方法和避坑经验完整分享出来。
2. 新版核心配置解析
2.1 安全过滤链配置变革
Spring Security 6.x最大的变化就是移除了WebSecurityConfigurerAdapter,改为通过SecurityFilterChain Bean来配置安全规则。这种函数式编程风格的配置更符合现代Java开发习惯:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
);
return http.build();
}
}
重要提示:新版的requestMatchers()替代了旧版的antMatchers(),且路径匹配规则更加严格。例如"/user"不再匹配"/user/"。
2.2 密码编码器最佳实践
6.x版本强化了密码安全策略,默认不再允许使用不安全的编码器。推荐配置方案:
java复制@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
这种委托编码器会根据密码前缀自动选择BCrypt、Pbkdf2等算法,存储格式类似:
code复制{bcrypt}$2a$10$N9qo8uLOickgx2ZMRZoMy...
3. 深度配置实战
3.1 OAuth2资源服务器配置
新版OAuth2资源服务器的配置更加简洁:
java复制@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.decoder(jwtDecoder())
)
);
return http.build();
}
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
}
3.2 方法级安全控制
方法级安全注解依然可用,但需要显式启用:
java复制@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}
然后在服务层使用:
java复制@PreAuthorize("hasRole('ADMIN') or #userId == authentication.name")
public User getUser(String userId) {
// ...
}
4. 常见问题解决方案
4.1 CSRF保护策略
在REST API场景下,通常需要禁用CSRF:
java复制http.csrf(csrf -> csrf.disable());
但对于传统Web应用,建议保持开启并配置Cookie策略:
java复制http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
4.2 跨域问题处理
新版CORS配置更加模块化:
java复制@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://trusted.com"));
config.setAllowedMethods(List.of("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
5. 高级安全配置技巧
5.1 动态权限控制
实现动态权限需要自定义评估逻辑:
java复制@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication auth, Object target, Object permission) {
// 自定义权限检查逻辑
}
}
// 配置类中注册
@Bean
MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
}
5.2 安全事件监控
Spring Security 6.x提供了更完善的事件发布机制:
java复制@Bean
ApplicationListener<AuthenticationSuccessEvent> successListener() {
return event -> {
String username = event.getAuthentication().getName();
log.info("Login success: {}", username);
// 记录登录日志
};
}
6. 性能优化方案
6.1 安全过滤器调优
通过调整过滤器顺序可以提升性能:
java复制@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/api/**")
// API专用配置
return http.build();
}
@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
http // 默认配置
return http.build();
}
6.2 会话管理策略
无状态API建议使用无会话策略:
java复制http.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
对于Web应用可以配置会话保护:
java复制http.sessionManagement(session -> session
.sessionFixation().migrateSession()
.maximumSessions(1)
.expiredUrl("/login?expired")
);
7. 测试配置要点
7.1 测试环境安全配置
测试时可以使用简化安全配置:
java复制@TestConfiguration
public class TestSecurityConfig {
@Bean
SecurityFilterChain testFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
)
.csrf(csrf -> csrf.disable());
return http.build();
}
}
7.2 Mock用户测试
在测试中快速模拟认证用户:
java复制@Test
@WithMockUser(roles = "ADMIN")
void testAdminEndpoint() {
// 测试代码
}
或者自定义用户详情:
java复制@Test
@WithUserDetails(
value = "customUser",
userDetailsServiceBeanName = "myUserDetailsService"
)
void testWithCustomUser() {
// 测试代码
}
8. 生产环境最佳实践
8.1 安全头配置
推荐的安全头配置方案:
java复制http.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'")
)
.frameOptions(frame -> frame
.sameOrigin()
)
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.preload(true)
.maxAgeInSeconds(63072000)
)
);
8.2 审计日志集成
配置安全审计日志:
java复制@Bean
AuditEventRepository auditEventRepository() {
return new InMemoryAuditEventRepository();
}
@Bean
AuditListener auditListener() {
return event -> {
// 自定义审计处理
};
}
9. 迁移注意事项
从5.x迁移到6.x时特别注意:
- 替换所有WebSecurityConfigurerAdapter的使用
- antMatchers()改为requestMatchers()
- 密码编码器必须显式配置
- CSRF令牌获取方式变化
- 移除已废弃的mvcMatchers()
我在实际迁移过程中发现,最棘手的部分是路径匹配规则的改变。新版的requestMatchers()对URL末尾斜杠的处理更加严格,需要仔细检查所有路径配置。