Spring Security
Spring Security 是 Spring 官方安全框架,提供认证(Authentication)和授权(Authorization)机制。
提示
安全框架核心概念、认证、授权、OAuth2
核心概念
| 概念 | 说明 |
|---|---|
| Authentication | 验证用户身份(你是谁) |
| Authorization | 验证用户权限(你能做什么) |
| Principal | 当前登录用户 |
| GrantedAuthority | 用户拥有的权限 |
| SecurityContext | 安全上下文,存储认证信息 |
核心组件
| 组件 | 说明 |
|---|---|
| SecurityFilterChain | 安全过滤器链 |
| UserDetailsService | 用户信息加载接口 |
| AuthenticationManager | 认证管理器 |
| PasswordEncoder | 密码加密器 |
| AccessDecisionManager | 访问决策管理器 |
快速开始
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**", "/login").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home", true)
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}认证流程
请求 → SecurityFilterChain → AuthenticationFilter
→ AuthenticationManager → AuthenticationProvider
→ UserDetailsService → 数据库验证
→ SecurityContextHolder 存储认证信息自定义登录
表单登录
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/doLogin")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
.permitAll();短信验证码登录
核心思路:自定义 AuthenticationFilter + AuthenticationToken + AuthenticationProvider。
public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public SmsAuthenticationFilter(AuthenticationManager authManager) {
super(new AntPathRequestMatcher("/login/mobile", "POST"));
this.setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) {
String mobile = request.getParameter("mobile");
String smsCode = request.getParameter("smsCode");
SmsAuthenticationToken token = new SmsAuthenticationToken(mobile, smsCode);
return getAuthenticationManager().authenticate(token);
}
}用户认证
实现 UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userMapper.findByUsername(username);
if (user == null) throw new UsernameNotFoundException("用户不存在");
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(),
AuthorityUtils.createAuthorityList(user.getRoles())
);
}
}权限控制
URL 权限
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
);方法级权限
@EnableMethodSecurity(prePostEnabled = true)
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() { }
@PostAuthorize("returnObject.username == authentication.name")
public User getUser(Long id) { }自定义权限评估器
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
// 自定义权限判断逻辑
return true;
}
@Override
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
return true;
}
}Session 管理
并发控制
http.sessionManagement(session -> session
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.expiredUrl("/session/expired")
);RememberMe
http.rememberMe(remember -> remember
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(1209600) // 14 天
.userDetailsService(userDetailsService)
);Session 共享
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisSessionConfig { }CSRF 防护
http.csrf(csrf -> csrf
.ignoringRequestMatchers("/api/**") // API 接口通常禁用
);模板中使用 Token:
<!-- Thymeleaf -->
<input type="hidden" name="_csrf" th:value="${_csrf.token}" />
<!-- AJAX -->
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': '${_csrf.token}' } });过滤器链
Spring Security 默认过滤器链(按顺序):
| 过滤器 | 功能 |
|---|---|
| SecurityContextPersistenceFilter | 安全上下文持久化 |
| HeaderWriterFilter | 写入安全头 |
| CorsFilter | CORS 处理 |
| CsrfFilter | CSRF 防护 |
| LogoutFilter | 登出处理 |
| UsernamePasswordAuthenticationFilter | 表单登录认证 |
| AnonymousAuthenticationFilter | 匿名认证 |
| SessionManagementFilter | Session 管理 |
| ExceptionTranslationFilter | 异常转换 |
| FilterSecurityInterceptor | 权限拦截 |
OAuth2
Spring Security OAuth2 支持第三方授权登录和 SSO,详见 SpringSecurityOAuth2。
常用注解
| 注解 | 说明 |
|---|---|
@EnableWebSecurity | 启用 Web 安全 |
@EnableMethodSecurity | 启用方法级安全 |
@PreAuthorize | 方法前权限检查 |
@PostAuthorize | 方法后权限检查 |
@Secured | 基于角色权限 |