Spring Security 核心功能
-
认证(Authentication)
-
功能:验证用户的身份是否合法。
-
实现:
- 使用
AuthenticationManager进行身份验证。 - 支持多种认证方式(用户名密码、OAuth2、JWT、LDAP 等)。
- 通过
UserDetailsService加载用户详细信息。
- 使用
-
-
授权(Authorization)
-
功能:确定用户是否有权限访问某资源。
-
实现:
- 基于 URL、方法、表达式的权限控制(
@PreAuthorize、@Secured)。 - 权限评估由
AccessDecisionManager完成。 - 配置
HttpSecurity管理请求级别的权限。
- 基于 URL、方法、表达式的权限控制(
-
-
会话管理
-
功能:管理用户会话状态,支持单点登录(SSO)和并发会话控制。
-
实现:
- 使用
SessionManagementConfigurer进行会话配置。 - 支持跨站请求防护(CSRF)、记住我功能(Remember-Me)。
- 使用
-
-
防护机制
- CSRF 防护:内置防御跨站请求伪造攻击机制。
- 密码存储:提供多种加密算法(如 BCrypt)存储用户密码。
- 安全头配置:如 X-Content-Type-Options、X-XSS-Protection、Strict-Transport-Security 等。
-
扩展性
- 自定义认证与授权:实现自定义的
AuthenticationProvider或AccessDecisionVoter。 - 支持第三方登录:通过 OAuth2.0 和 OpenID Connect 实现社交登录。
- 细粒度控制:如针对特定角色、IP 的访问规则配置。
- 自定义认证与授权:实现自定义的
Spring Security 实现原理
-
过滤器链(Filter Chain)
-
核心机制是基于 Servlet 过滤器的链式调用。
-
DelegatingFilterProxy将所有请求代理到SecurityFilterChain。 -
常见过滤器:
UsernamePasswordAuthenticationFilter:处理用户名密码登录。BasicAuthenticationFilter:处理 HTTP Basic 认证。CsrfFilter:检查 CSRF 令牌。ExceptionTranslationFilter:处理认证/授权异常。
-
-
认证流程
- 用户提交认证请求(如表单登录)。
AuthenticationFilter拦截请求并构造Authentication对象。- 将
Authentication交给AuthenticationManager。 AuthenticationManager调用多个AuthenticationProvider验证身份。- 如果认证成功,返回认证后的
Authentication对象存入SecurityContextHolder。
-
授权流程
- 请求经过过滤器链后,进入
AccessDecisionManager。 AccessDecisionManager调用AccessDecisionVoter判断是否有权限访问资源。- 如果无权限,抛出
AccessDeniedException。
- 请求经过过滤器链后,进入
-
密码加密与校验
- 默认使用
PasswordEncoder(如 BCrypt)对密码进行加密存储。 - 校验时,使用加密后的密码进行匹配,确保安全性。
- 默认使用
-
会话管理
- 通过
SecurityContextPersistenceFilter维护会话上下文。 - 支持会话过期、并发会话限制。
- 通过
案例:实现用户认证和授权
功能描述
实现一个简单的用户认证和授权系统:
- 用户通过用户名和密码登录。
- 系统校验用户名密码的合法性,认证通过后访问受保护的资源。
- 只有具备特定角色的用户才能访问某些特定的接口。
实现步骤
1. 引入依赖
添加 Spring Security 相关依赖(pom.xml):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 配置认证逻辑
自定义用户认证逻辑,加载用户数据。
代码:UserDetailsService 实现
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 密码加密
}
@Bean
public UserDetailsService userDetailsService() {
// 在内存中创建用户
UserDetails user1 = User.builder()
.username("admin")
.password(passwordEncoder().encode("password")) // 加密后的密码
.roles("ADMIN") // 赋予角色
.build();
UserDetails user2 = User.builder()
.username("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user1, user2);
}
}
3. 配置授权规则
配置 URL 的权限控制逻辑。
代码:HTTP 请求的授权配置
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityFilterConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable() // 关闭 CSRF,仅供演示
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 仅 ADMIN 可访问
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN") // USER 和 ADMIN 可访问
.antMatchers("/public/**").permitAll() // 所有人都可访问
.anyRequest().authenticated() // 其他请求需要认证
.and()
.formLogin() // 表单登录
.loginPage("/login") // 自定义登录页
.permitAll()
.and()
.logout() // 支持注销
.permitAll();
return http.build();
}
}
4. 构建 Controller
代码:Controller 示例
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/public/hello")
public String publicEndpoint() {
return "Hello, Public!";
}
@GetMapping("/user/hello")
public String userEndpoint() {
return "Hello, User!";
}
@GetMapping("/admin/hello")
public String adminEndpoint() {
return "Hello, Admin!";
}
}
案例分析:实现的认证和授权
-
认证流程
-
用户登录:
- 用户通过表单提交用户名和密码。
UsernamePasswordAuthenticationFilter捕获登录请求,将用户名和密码封装成UsernamePasswordAuthenticationToken。- 通过
AuthenticationManager验证,调用UserDetailsService加载用户信息。 - 验证成功后,将用户的认证信息存储在
SecurityContextHolder中。
-
-
授权流程
-
请求访问接口:
- 每个 HTTP 请求都会经过
SecurityFilterChain。 - 根据配置的权限规则(
antMatchers),判断用户是否具备访问权限。 - 如果用户权限不匹配,返回 403 Forbidden;否则允许访问。
- 每个 HTTP 请求都会经过
-
运行结果
-
访问
/public/hello:任何用户都可以访问。 -
访问
/user/hello:- 未登录时跳转到登录页面。
- 登录
user/password后,可以访问。
-
访问
/admin/hello:- 未登录或登录普通用户
user无权限。 - 登录
admin/password后可以访问。
- 未登录或登录普通用户