1. Spring Security核心架构总览
1.1 安全过滤器链(Security Filter Chain)
- DelegatingFilterProxy
Spring Security入口,将请求委托给FilterChainProxy,后者管理多个安全过滤器链。 - java
// 核心注册逻辑
public class SpringSecurityFilterChainConfiguration {
@Bean
public Filter springSecurityFilterChain() throws Exception {
return http.build(); // 构建FilterChainProxy
}
}
- 过滤器链典型组成
- plaintext
SecurityContextPersistenceFilter → LogoutFilter → UsernamePasswordAuthenticationFilter →
BasicAuthenticationFilter → AuthorizationFilter → ... → ExceptionTranslationFilter → FilterSecurityInterceptor
1.2 核心组件交互关系
plaintext
HTTP Request → Security Filter Chain → AuthenticationManager → AuthenticationProvider →
UserDetailsService → AccessDecisionManager → AccessDecisionVoter
2. 认证机制底层实现
2.1 认证流程源码追踪
- UsernamePasswordAuthenticationFilter
拦截/login POST请求,提取用户名密码生成UsernamePasswordAuthenticationToken。 - java
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
String username = obtainUsername(request);
String password = obtainPassword(request);
// 创建未认证Token
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
return this.getAuthenticationManager().authenticate(authRequest);
}
- ProviderManager与DaoAuthenticationProvider
ProviderManager遍历AuthenticationProvider列表,DaoAuthenticationProvider通过UserDetailsService加载用户并校验密码。 - java
// DaoAuthenticationProvider.authenticate()
UserDetails user = this.userDetailsService.loadUserByUsername(username);
this.preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication);
2.2 密码存储与验证
- PasswordEncoder演化
- NoOpPasswordEncoder(明文,已废弃) → BCryptPasswordEncoder(推荐) → DelegatingPasswordEncoder(多算法兼容)
- 关键源码:PasswordEncoderFactories.createDelegatingPasswordEncoder()
3. 授权机制深度解析
3.1 访问控制决策链
- FilterSecurityInterceptor
最后一个安全过滤器,触发授权检查,委托给AccessDecisionManager。 - java
// AbstractSecurityInterceptor.beforeInvocation()
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
this.accessDecisionManager.decide(authenticated, object, attributes);
- 基于投票的决策模型
- AffirmativeBased(默认):一票通过即放行
- RoleVoter实现:检查ConfigAttribute前缀ROLE_,比对用户权限
- java
public int vote(Authentication authentication, Object object,
Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attribute : attributes) {
if (attribute.getAttribute().startsWith("ROLE_")) {
// 权限比对逻辑
}
}
}
3.2 方法级安全实现
- @PreAuthorize与AOP织入
- 启用注解:@EnableGlobalMethodSecurity(prePostEnabled = true)
- 核心类:MethodSecurityInterceptor(基于AOP Alliance拦截器)
- 表达式解析:PreInvocationAuthorizationAdviceVoter处理SpEL表达式
4. 安全上下文与线程绑定
4.1 SecurityContextHolder策略
- 存储模式
- java
// 默认使用ThreadLocal策略
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
- 跨线程传递
需手动传递SecurityContext,或使用DelegatingSecurityContextRunnable包装任务
4.2 Session管理机制
- SessionFixationProtection
认证成功后更换Session ID(默认changeSessionId策略) - java
// SessionManagementFilter.doFilter()
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
5. 扩展点与定制化开发
5.1 自定义认证逻辑
- 实现AuthenticationProvider
- java
public class CustomAuthProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication auth) {
// 自定义认证逻辑
return new CustomAuthenticationToken(...);
}
@Override
public boolean supports(Class<?> authentication) {
return CustomAuthenticationToken.class.isAssignableFrom(authentication);
}
}
5.2 自定义访问控制
- 实现AccessDecisionVoter
- java
public class IPRangeVoter implements AccessDecisionVoter<FilterInvocation> {
public int vote(Authentication authentication, FilterInvocation fi,
Collection<ConfigAttribute> attributes) {
String clientIP = fi.getRequest().getRemoteAddr();
// IP白名单校验
}
}
6. 性能优化实践
6.1 安全过滤器优化
- 禁用不使用的过滤器
- java
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().formLogin().disable();
}
}
6.2 缓存策略
- UserDetails缓存
- java
@Bean
public UserDetailsService userDetailsService() {
return new CachingUserDetailsService(new JdbcDaoImpl());
}
7. 源码调试与问题排查
7.1 关键断点位置
- 认证流程
UsernamePasswordAuthenticationFilter.attemptAuthentication()
DaoAuthenticationProvider.retrieveUser() - 授权流程
FilterSecurityInterceptor.beforeInvocation()
AffirmativeBased.decide()
7.2 日志配置
properties
# 开启详细日志
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.web=TRACE
附录:高频问题解析
- 如何解决AnonymousAuthenticationFilter与自定义Filter的冲突?
→ 检查过滤器顺序,确保自定义Filter在AnonymousAuthenticationFilter之后 - AccessDeniedException与AuthenticationException的区别?
→ 前者表示已认证但无权访问,后者表示未认证或认证失败 - OAuth2与Spring Security的集成原理?
→ 通过ResourceServerConfigurer和AuthorizationServerConfigurer扩展默认配置