在 Spring Security 中,过滤器链是一系列安全过滤器,它们按照特定顺序处理传入的 HTTP 请求。这些过滤器根据定义的安全规则决定是否允许请求继续、进行身份验证或拒绝访问。
Spring Security 的过滤器链是 Servlet 过滤器机制的一部分,由 FilterChainProxy 实现。链中的每个过滤器执行特定的安全相关功能,例如身份验证、授权或会话管理。
核心概念
1. FilterChainProxy:
• 作为安全过滤器的调度器。
• 根据请求的 URL 将请求委托给一个或多个过滤器链。
2. 安全过滤器:
• 例如 UsernamePasswordAuthenticationFilter、BasicAuthenticationFilter、SecurityContextPersistenceFilter 等。
• 每个过滤器在安全流程中执行特定任务。
3. 过滤器链执行:
• 请求依次通过过滤器链,每个过滤器都有机会处理或修改请求/响应。
• 如果任何过滤器拒绝访问,链将停止。
4. 安全配置:
• 使用 Spring Security 的 DSL(领域特定语言)或 XML 配置文件来配置过滤器。
示例场景
假设有以下安全需求:
- •
/public/**:无需身份验证。 - •
/user/**:仅允许已认证用户访问。 - •
/admin/**:仅允许具有ADMIN角色的用户访问。
安全配置示例:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // 无需身份验证
.antMatchers("/user/**").authenticated() // 需要身份验证
.antMatchers("/admin/**").hasRole("ADMIN") // 需要 ADMIN 角色
.anyRequest().denyAll() // 拒绝所有其他请求
.and()
.formLogin(); // 启用基于表单的登录
}
}过滤器链执行流程:
1. 传入请求:/admin/dashboard
2. 过滤器链:
• SecurityContextPersistenceFilter:恢复安全上下文。
• UsernamePasswordAuthenticationFilter:处理登录凭据。
• BasicAuthenticationFilter:处理 HTTP 基本身份验证(如果适用)。
• ExceptionTranslationFilter:捕获异常并将其转换为 HTTP 响应。
• FilterSecurityInterceptor:对 /admin/** URL 强制执行访问控制。
如果用户已认证并具有 ADMIN 角色,请求将继续到控制器。否则,链将停止,并返回错误响应(例如 403 Forbidden)。
查看 Spring Boot 中的过滤器链
在 Spring Boot 应用程序中,可以通过启用 Spring Security 的调试日志来查看配置的过滤器链:
logging.level.org.springframework.security=DEBUG
常用的安全过滤器及其职责
以下是 Spring Security 中常用的安全过滤器及其职责和执行顺序:
1. WebAsyncManagerIntegrationFilter:将 Spring Security 与 Spring MVC 的异步请求处理集成。
2. SecurityContextPersistenceFilter:管理 SecurityContext 的生命周期(在处理请求前检索并在处理后保存)。
3. HeaderWriterFilter:向响应中添加安全相关的 HTTP 头(例如 X-Frame-Options、X-XSS-Protection)。
4. CsrfFilter:强制执行防止跨站请求伪造(CSRF)攻击的保护。
5. LogoutFilter:处理用户注销,清除 SecurityContext 并无效化会话。
6. UsernamePasswordAuthenticationFilter:通过验证用户名和密码凭据处理基于表单的登录身份验证。
7. ConcurrentSessionFilter:管理并发会话,如果配置了会话限制,则强制执行。
8. BearerTokenAuthenticationFilter:处理基于令牌的身份验证,例如 OAuth 2.0 Bearer 令牌。
9. BasicAuthenticationFilter:处理 HTTP 基本身份验证(验证 Authorization 头中的凭据)。
10. RequestCacheAwareFilter:在成功认证后恢复原始请求 URL(如果请求被拦截)。
11. SecurityContextHolderAwareRequestFilter:向请求对象提供 Spring Security 的 SecurityContext 和身份验证详细信息。
12. AnonymousAuthenticationFilter:如果用户未认证,则提供默认的匿名身份验证对象。
13. SessionManagementFilter:管理与会话相关的任务,例如会话无效化和跟踪。
14. ExceptionTranslationFilter:处理访问拒绝异常和身份验证异常,通过重定向或发送适当的响应。
15. FilterSecurityInterceptor:使用访问控制策略对受保护资源执行最终的访问控制检查。
示例:UsernamePasswordAuthenticationFilter
用户名-密码身份验证流程是 Spring Security 中验证用户凭据(用户名和密码)以允许或拒绝访问受保护资源的过程。该流程由多个组件协同工作,包括过滤器、管理器和提供程序。
以下是该流程的逐步分解:
1. 请求发起:客户端向受保护资源(例如 /login)发送 HTTP 请求。
2. 拦截请求:UsernamePasswordAuthenticationFilter 拦截请求。
3. 创建 Authentication 对象:过滤器创建一个 Authentication 对象(通常是 UsernamePasswordAuthenticationToken)。
4. 委托给 AuthenticationManager:过滤器将身份验证任务委托给 AuthenticationManager。
5. 身份验证提供程序:AuthenticationManager 将实际身份验证委托给一个或多个 AuthenticationProvider 实例。
6. 验证凭据:DaoAuthenticationProvider 使用 UserDetailsService 从数据源加载用户详细信息,并使用 PasswordEncoder 验证密码。
7. 成功认证:如果认证成功,Authentication 对象被设置到 SecurityContext 中,用户被重定向到原始请求的 URL 或默认的成功 URL。
8. 认证失败:如果认证失败,抛出 AuthenticationException,用户被重定向到登录页面并显示错误消息。
使用 SecurityFilterChain 配置
以下是如何使用 SecurityFilterChain 实现用户名-密码身份验证流程的示例:
配置类:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/public/**").permitAll() // 公共端点
.anyRequest().authenticated() // 保护所有其他端点
.and()
.formLogin() // 启用基于表单的登录
.loginPage("/login") // 自定义登录页面
.permitAll()
.and()
.logout() // 启用注销功能
.permitAll();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 用于密码哈希的密码编码器
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}用户详情配置:
@Configuration
public class UserDetailsConfig {
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}自定义登录页面:
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login"; // 指向 login.html
}
}login.html:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form action="/login" method="post">
<div>
<label for="username">Username:</label>
<input type="text" id="username" name="username">
</div>
<div>
<label for="password">Password:</label>
<input type="password" id="password" name="password">
</div>
<div>
<button type="submit">Login</button>
</div>
</form>
</body>
</html>总结
Spring Security 的过滤器链机制为处理 HTTP 请求提供了强大的安全控制能力。通过合理配置过滤器链,可以实现身份验证、授权、会话管理等功能,确保应用程序的安全性。