Spring Security 中的过滤器链(Filter Chain)

在 Spring Security 中,过滤器链是一系列安全过滤器,它们按照特定顺序处理传入的 HTTP 请求。这些过滤器根据定义的安全规则决定是否允许请求继续、进行身份验证或拒绝访问。

Spring Security 的过滤器链是 Servlet 过滤器机制的一部分,由 FilterChainProxy 实现。链中的每个过滤器执行特定的安全相关功能,例如身份验证、授权或会话管理。

核心概念

1. FilterChainProxy

• 作为安全过滤器的调度器。

• 根据请求的 URL 将请求委托给一个或多个过滤器链。

2. 安全过滤器

• 例如 UsernamePasswordAuthenticationFilterBasicAuthenticationFilterSecurityContextPersistenceFilter 等。

• 每个过滤器在安全流程中执行特定任务。

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-OptionsX-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 请求提供了强大的安全控制能力。通过合理配置过滤器链,可以实现身份验证、授权、会话管理等功能,确保应用程序的安全性。

请登录后发表评论

    没有回复内容