UsernamePasswordAuthenticationFilter
、FilterSecurityInterceptor
)实现安全控制。SecurityContextPersistenceFilter
(管理安全上下文)、AuthenticationFilter
(处理认证请求)、AuthorizationFilter
(处理授权逻辑)。AuthenticationManager
,负责处理认证请求,默认实现为 ProviderManager
。AuthenticationProvider
):如 DaoAuthenticationProvider
(基于数据库认证)、OAuth2AuthenticationProvider
(基于 OAuth2 认证)。SecurityContextHolder
存储当前用户的认证信息(Authentication
对象),贯穿整个请求生命周期。
org.springframework.boot
spring-boot-starter-security
user
,密码在启动日志中生成。创建 SecurityConfig
类,继承 WebSecurityConfigurerAdapter
(Spring Boot 2.7+ 需实现 SecurityFilterChain
):
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 表单登录配置
.formLogin()
.loginPage("/login") // 自定义登录页
.defaultSuccessUrl("/home", true) // 登录成功跳转页
.permitAll() // 允许匿名访问登录页
.and()
// 权限控制
.authorizeHttpRequests()
.requestMatchers("/public").permitAll() // 公开接口
.requestMatchers("/admin").hasRole("ADMIN") // 需要 ADMIN 角色
.anyRequest().authenticated() // 其他请求需认证
.and()
// 注销配置
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true)
.and()
// 关闭 CSRF(测试环境可选,生产环境需保留)
.csrf().disable();
return http.build();
}
// 内存用户(测试用,生产环境需从数据库加载)
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user")
.password(passwordEncoder().encode("123456"))
.roles("USER")
.build();
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN", "USER")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
/admin
,未认证时重定向到登录页。UsernamePasswordAuthenticationFilter
拦截,封装为 UsernamePasswordAuthenticationToken
。ProviderManager
调用 UserDetailsService
加载用户信息,对比密码(需匹配 PasswordEncoder
)。Authentication
对象,存入 SecurityContextHolder
,允许访问资源。FilterSecurityInterceptor
根据配置的权限规则(如 hasRole
)校验用户权限。UserDetailsService
接口,从数据库或第三方系统加载用户信息。ProviderManager
组合多个 AuthenticationProvider
。Authorization: Bearer
)。SecurityContext
。io.jsonwebtoken:jjwt
。ROLE_ADMIN
、ROLE_USER
。user:read
、order:create
,基于 Spring Security ACL
或自定义注解实现。authorizeHttpRequests
中使用表达式控制访问: .authorizeHttpRequests(authz -> authz
.requestMatchers("/admin").hasRole("ADMIN") // 需 ADMIN 角色
.requestMatchers("/user").hasAnyRole("USER", "ADMIN") // 需 USER 或 ADMIN 角色
.requestMatchers("/api/**").hasAuthority("user:read") // 需 user:read 权限
.requestMatchers("/profile").authenticated() // 已认证用户
.requestMatchers("/public").permitAll() // 公开访问
);
hasIpAddress("192.168.1.1")
(限制 IP 访问)、@beanName.method()
(调用自定义 Bean 逻辑)。http.csrf().enable()
。_csrf
令牌,验证请求来源的合法性。http.csrf().disable()
。.sessionManagement()
.maximumSessions(1) // 单用户最大会话数
.maxSessionsPreventsLogin(true) // 超过限制时拒绝新登录
.and()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话(如 JWT 场景)
PasswordEncoder
接口,推荐使用 BCryptPasswordEncoder
。AbstractAuthenticationProcessingFilter
,处理特殊认证方式(如短信验证码、指纹识别)。public class SMSCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public SMSCodeAuthenticationFilter() {
super(new AntPathRequestMatcher("/login/sms", "POST")); // 匹配短信登录路径
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
String phone = request.getParameter("phone");
String code = request.getParameter("code");
SMSCodeAuthenticationToken token = new SMSCodeAuthenticationToken(phone, code);
return getAuthenticationManager().authenticate(token);
}
}
AccessDecisionManager
,自定义复杂授权逻辑(如多因素认证、动态权限)。SecurityFilterChain
、UserDetailsService
等 Bean。application.properties
中添加 spring.security.enabled=false
(谨慎使用)。@PreAuthorize
、@PostAuthorize
注解实现方法级权限控制: @RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users")
@PreAuthorize("hasAuthority('user:read')")
public List getUsers() { ... }
@PostMapping("/users")
@PreAuthorize("hasAuthority('user:create') and @securityService.isAdmin()") // 调用自定义 Bean
public User createUser(@RequestBody User user) { ... }
}
UserDetails
,减少数据库查询: @Service
@CacheConfig(cacheNames = "userDetails")
public class CachedUserDetailsService implements UserDetailsService {
@Override
@Cacheable(key = "#username")
public UserDetails loadUserByUsername(String username) {
return userRepository.findByUsername(username); // 从数据库加载
}
}
/actuator/metrics
)监控系统安全状态。GET /users
:需 ADMIN
角色。GET /users/me
:需已认证用户(authenticated
)。PUT /users/me
:需 USER
角色。public class JwtUtils {
private static final String SECRET = "your-secret-key-32-bytes-long";
private static final long EXPIRATION_TIME = 86400000L; // 24小时
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}
public static String validateToken(String token) {
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
} catch (Exception e) {
return null;
}
}
}
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
String username = JwtUtils.validateToken(token);
if (username != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtAuthenticationFilter(userDetailsService), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/auth/register", "/auth/login").permitAll()
.requestMatchers("/users").hasRole("ADMIN")
.requestMatchers("/users/me").authenticated()
.anyRequest().denyAll()
);
return http.build();
}
Spring Security 的学习路径可概括为:基础配置 → 认证授权核心 → 自定义扩展 → 微服务集成 → 性能优化。建议从简单的表单登录开始,逐步尝试 JWT、OAuth2 等复杂场景,并通过实战项目巩固知识。遇到问题时,结合官方文档和调试工具(如断点跟踪过滤器链)分析流程,逐步掌握其底层逻辑。