一、基础概念与核心原理
1. Spring Security 是什么?
- 定位:Spring 生态中的安全框架,用于实现 Web 应用的身份验证(Authentication)和授权(Authorization)。
- 核心功能:
- 防止未经授权的访问(如登录认证)。
- 细粒度的权限控制(如角色 / 权限管理)。
- 支持多种认证方式(如用户名密码、OAuth2、JWT 等)。
- 防御常见安全攻击(如 CSRF、XSS、Session 固定等)。
2. 核心架构与术语
- 过滤器链(Filter Chain):
- Spring Security 通过一系列过滤器(如
UsernamePasswordAuthenticationFilter
、FilterSecurityInterceptor
)实现安全控制。 - 核心过滤器:
SecurityContextPersistenceFilter
(管理安全上下文)、AuthenticationFilter
(处理认证请求)、AuthorizationFilter
(处理授权逻辑)。
- Spring Security 通过一系列过滤器(如
- 认证管理器(Authentication Manager):
- 核心接口
AuthenticationManager
,负责处理认证请求,默认实现为ProviderManager
。 - 认证提供者(
AuthenticationProvider
):如DaoAuthenticationProvider
(基于数据库认证)、OAuth2AuthenticationProvider
(基于 OAuth2 认证)。
- 核心接口
- 安全上下文(Security Context):
- 通过
SecurityContextHolder
存储当前用户的认证信息(Authentication
对象),贯穿整个请求生命周期。
- 通过
二、入门实践:快速搭建安全应用
1. 环境准备
- 添加依赖(Spring Boot 场景):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
- 默认行为:引入依赖后,Spring Security 会自动启用表单登录和基本认证,默认用户名为
user
,密码在启动日志中生成。
2. 基础配置:自定义认证规则
创建 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();
}
}
3. 核心流程解析
- 用户访问受保护资源:如
/admin
,未认证时重定向到登录页。 - 提交登录表单:用户名密码通过
UsernamePasswordAuthenticationFilter
拦截,封装为UsernamePasswordAuthenticationToken
。 - 认证处理:
ProviderManager
调用UserDetailsService
加载用户信息,对比密码(需匹配PasswordEncoder
)。 - 认证成功:生成
Authentication
对象,存入SecurityContextHolder
,允许访问资源。 - 授权校验:
FilterSecurityInterceptor
根据配置的权限规则(如hasRole
)校验用户权限。
三、核心模块深度解析
1. 认证模块(Authentication)
- 认证方式扩展:
- 自定义认证逻辑:实现
UserDetailsService
接口,从数据库或第三方系统加载用户信息。 - 多认证方式:如同时支持用户名密码和 OAuth2 登录,通过
ProviderManager
组合多个AuthenticationProvider
。
- 自定义认证逻辑:实现
- JWT 认证:
- 替换传统 Session-Cookie 模式,使用 JWT 令牌实现无状态认证。
- 关键步骤:
- 登录时生成 JWT 令牌(含用户信息、过期时间等)。
- 客户端携带令牌至请求头(
Authorization: Bearer <token>
)。 - 自定义过滤器解析令牌,验证有效性并设置
SecurityContext
。
- 常用库:
io.jsonwebtoken:jjwt
。
2. 授权模块(Authorization)
- 权限模型:
- 角色(Role):粗粒度权限,如
ROLE_ADMIN
、ROLE_USER
。 - 权限(Permission):细粒度权限,如
user:read
、order:create
,基于Spring Security ACL
或自定义注解实现。
- 角色(Role):粗粒度权限,如
- 表达式语言(Spring EL):
- 在
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 逻辑)。
- 在
3. 安全配置进阶
- CSRF 防护:
- 开启 CSRF(默认启用):
http.csrf().enable()
。 - 原理:通过在表单中添加
_csrf
令牌,验证请求来源的合法性。 - 例外场景:REST API 可禁用 CSRF(使用 JWT 时):
http.csrf().disable()
。
- 开启 CSRF(默认启用):
- 会话管理(Session Management):
- 配置会话策略:
.sessionManagement() .maximumSessions(1) // 单用户最大会话数 .maxSessionsPreventsLogin(true) // 超过限制时拒绝新登录 .and() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话(如 JWT 场景)
- 配置会话策略:
- 密码加密:
- 必须使用强加密算法(如 BCrypt、SCrypt),避免明文存储。
- Spring Security 提供
PasswordEncoder
接口,推荐使用BCryptPasswordEncoder
。
四、高级主题与扩展
1. 自定义认证与授权
- 自定义认证过滤器:
- 继承
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
,自定义复杂授权逻辑(如多因素认证、动态权限)。
- 实现
2. 与其他框架集成
- Spring Boot + Security:
- 自动配置:Spring Boot 自动配置
SecurityFilterChain
、UserDetailsService
等 Bean。 - 关闭自动配置:在
application.properties
中添加spring.security.enabled=false
(谨慎使用)。
- 自动配置:Spring Boot 自动配置
- Spring MVC 与 Security:
- 在 MVC 控制器中使用
@PreAuthorize
、@PostAuthorize
注解实现方法级权限控制:@RestController @RequestMapping("/api") public class UserController { @GetMapping("/users") @PreAuthorize("hasAuthority('user:read')") public List<User> getUsers() { ... } @PostMapping("/users") @PreAuthorize("hasAuthority('user:create') and @securityService.isAdmin()") // 调用自定义 Bean public User createUser(@RequestBody User user) { ... } }
- 在 MVC 控制器中使用
- 微服务场景下的安全:
- 使用 Spring Security OAuth2 + JWT 实现分布式认证中心(如 Auth Server)。
- 资源服务器(Resource Server)通过解析 JWT 令牌校验权限。
3. 性能优化与监控
- 缓存认证信息:
- 使用 Spring Cache 缓存
UserDetails
,减少数据库查询:@Service @CacheConfig(cacheNames = "userDetails") public class CachedUserDetailsService implements UserDetailsService { @Override @Cacheable(key = "#username") public UserDetails loadUserByUsername(String username) { return userRepository.findByUsername(username); // 从数据库加载 } }
- 使用 Spring Cache 缓存
- 监控与指标:
- 集成 Micrometer,暴露安全相关指标(如认证成功率、授权失败次数)。
- 通过 Actuator 端点(如
/actuator/metrics
)监控系统安全状态。
五、实战项目:构建安全的 RESTful API
需求场景
- 设计一个用户管理系统,包含以下安全需求:
- 使用 JWT 实现无状态认证。
- 支持用户注册、登录、修改密码。
- 管理员可查看所有用户,普通用户只能查看自己的信息。
技术方案
- 认证流程:
- 注册:用户提交用户名、密码,存储至数据库(密码加密)。
- 登录:返回 JWT 令牌,有效期 24 小时。
- 刷新令牌:使用 Refresh Token 机制(可选)。
- 授权规则:
GET /users
:需ADMIN
角色。GET /users/me
:需已认证用户(authenticated
)。PUT /users/me
:需USER
角色。
关键实现
- JWT 工具类:
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; } } }
- JWT 认证过滤器:
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 等复杂场景,并通过实战项目巩固知识。遇到问题时,结合官方文档和调试工具(如断点跟踪过滤器链)分析流程,逐步掌握其底层逻辑。