SpringSecurity 核心概念
SpringSecurity 是一个功能强大且高度可定制的身份验证和访问控制框架,专注于为 Java 应用程序提供安全性。其核心功能围绕身份验证(Authentication)和授权(Authorization)展开。
身份验证是确认用户身份的过程,通常通过用户名密码、OAuth2、JWT 等方式实现。授权是确定已验证用户拥有哪些权限,例如访问特定资源或执行某些操作。
认证流程剖析
SpringSecurity 的认证流程主要由一系列过滤器链组成。核心过滤器包括 UsernamePasswordAuthenticationFilter(处理表单登录)、BasicAuthenticationFilter(处理 HTTP Basic 认证)等。认证过程最终由 AuthenticationManager 协调,委托给 ProviderManager 和具体的 AuthenticationProvider 实现。
认证成功后,会生成 Authentication 对象并存入 SecurityContextHolder,供后续授权流程使用。默认使用 ThreadLocal 存储安全上下文,确保线程安全。
授权机制解析
授权通过 AccessDecisionManager 实现,核心策略包括:
- 基于投票的
AffirmativeBased(一票通过即可) - 一致性通过的
UnanimousBased(全部投票通过) - 多数通过的
ConsensusBased
权限判断通常使用 hasRole()、hasAuthority() 等表达式,或通过注解如 @PreAuthorize 实现方法级安全控制。配置示例:
java
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated();
JWT 集成实践
JWT(JSON Web Token)是一种无状态的认证方案,适合分布式系统。集成步骤:
创建 JWT 工具类处理令牌生成/验证:
java
public class JwtTokenUtil {
private String secret = "your-secret-key";
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600*1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
配置 JWT 过滤器:
java
public class JwtRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
String token = extractToken(request);
if (token != null && jwtUtil.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
OAuth2 集成方案
SpringSecurity 提供完整的 OAuth2 支持,包括客户端和资源服务器配置:
资源服务器配置示例:
java
@EnableResourceServer
@Configuration
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenServices(tokenServices());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("shared-secret");
return converter;
}
}
客户端配置示例:
java
@EnableOAuth2Client
@Configuration
public class OAuth2ClientConfig {
@Bean
public OAuth2RestTemplate oauth2RestTemplate(
OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
}
安全配置最佳实践
生产环境建议配置:
- 启用 CSRF 防护(对于有状态的 web 应用)
- 配置 CORS 策略
- 强制 HTTPS
- 设置严格的内容安全策略
- 使用安全密码编码器:
java
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
典型安全配置示例:
java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().ignoringAntMatchers("/api/**")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
}
}