★ Spring Security 认证流程与过滤器链是如何工作的?

结论先行:Spring Security 基于 Servlet 过滤器链实现,核心是 FilterChainProxy 按顺序执行一组 SecurityFilter。认证类过滤器(如 UsernamePasswordAuthenticationFilter)负责“取凭证→问 AuthenticationManager→写 SecurityContext”;授权由 AuthorizationFilter 在链路末尾裁决。回答框架:一条链、两类过滤器(认证/授权)、一个上下文。

一、过滤器链架构

部件作用
DelegatingFilterProxy把 Servlet 过滤器委托给 Spring 容器中的 Bean
FilterChainProxy持有并调度所有 SecurityFilterChain
SecurityFilterChain一组有序过滤器 + 请求匹配规则
SecurityContextHolder保存当前认证信息(默认 ThreadLocal)

Security 6.x 起以 Bean 方式声明链,配置风格改为 lambda:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(auth -> auth
          .requestMatchers("/login", "/public/**").permitAll()
          .anyRequest().authenticated())
      .formLogin(Customizer.withDefaults())
      .csrf(csrf -> csrf.disable());
    return http.build();
}

二、表单认证主流程

  1. 请求进入 UsernamePasswordAuthenticationFilter(默认拦截 /login POST);
  2. 从请求中取 username/password,构造未认证的 UsernamePasswordAuthenticationToken;
  3. 交给 AuthenticationManager(默认 ProviderManager)→ 遍历 AuthenticationProvider;
  4. DaoAuthenticationProvider 调 UserDetailsService.loadUserByUsername 拿用户,再用 PasswordEncoder 比对密码;
  5. 成功 → 生成已认证 Token 写入 SecurityContextHolder,走成功处理器(写 Session、跳转);
  6. 失败 → 清上下文,走 AuthenticationFailureHandler。
@Bean
UserDetailsService users() {
    UserDetails u = User.withUsername("admin")
            .password("{bcrypt}$2a$10$...")   // 生产用 BCrypt
            .roles("ADMIN").build();
    return new InMemoryUserDetailsManager(u);
}

三、授权与细节

  • 授权过滤器:Security 6 用 AuthorizationFilter(配合 requestMatchers 规则),老版本 FilterSecurityInterceptor 已废弃;
  • 匿名访问也会生成 AnonymousAuthenticationToken,因此“未登录”不等于“无 Authentication”;
  • 无状态场景:加 sessionManagement(s -> s.sessionCreationPolicy(STATELESS)) 并禁用 CSRF,令牌交给自定义 JWT 过滤器解析。

常见追问 / 记忆点

  • 追问:多个 SecurityFilterChain 如何匹配?答:按声明的顺序逐个 match,第一条命中的链生效,可用 securityMatcher 限定路径。
  • 追问:为什么自定义过滤器要放在指定位置?答:认证过滤器需在授权过滤器之前执行,用 addFilterBefore/After 精确插入。
  • 记忆点:一条 FilterChainProxy;认证=取凭证→AuthenticationManager→写上下文;授权在最后裁决。
笔记加载中…