You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中Cookie认证触发自定义AuthenticationProvider的问题及疑问

Spring Security 认证问题排查与实践解答

场景说明

用户实现的认证流程为:用户通过一次性临时URL获取Cookie,随后使用该Cookie作为认证令牌访问受保护资源。已实现CookieAuthenticationFilter、UserAuthProvider和SecurityConfig三个组件,但UserAuthProvider的authenticate方法未被触发,使用版本为Spring Boot 3.3.1。以下针对三个疑问逐一解答:


1. 遗漏的配置或代码

当前代码中,CookieAuthenticationFilter直接将PreAuthenticatedAuthenticationToken放入SecurityContext,但Spring Security不会自动触发AuthenticationProvider的认证逻辑,需要显式调用AuthenticationManager的authenticate方法来完成认证流程。具体修改如下:

修改CookieAuthenticationFilter,注入并调用AuthenticationManager

public class CookieAuthenticationFilter extends OncePerRequestFilter {

    private final AuthenticationManager authenticationManager;

    // 构造方法注入AuthenticationManager
    public CookieAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
        FilterChain filterChain) throws ServletException, IOException {
            Cookie cookie = Stream.of(Optional.ofNullable(request.getCookies())
                .orElse(new Cookie[0]))
                .filter(entry -> "token".equals(entry.getName()))
                .findFirst()
                .orElse(null);
           
            // 创建认证请求令牌
            Authentication authRequest = new PreAuthenticatedAuthenticationToken(
                cookie != null ? cookie.getValue() : "",
                null);
            
            // 触发认证流程,调用UserAuthProvider的authenticate方法
            Authentication authResult = authenticationManager.authenticate(authRequest);
            
            // 将认证结果存入安全上下文
            SecurityContextHolder.getContext().setAuthentication(authResult);

            filterChain.doFilter(request, response);
    }

}

修改SecurityConfig,传递AuthenticationManager给过滤器

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http, UserAuthProvider userAuthProvider) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        builder.authenticationProvider(userAuthProvider);
        return builder.build();
    }

    @Bean
    // 注入AuthenticationManager,移除无需使用的HttpSession参数
    public SecurityFilterChain securityFilterChain(HttpSecurity security, AuthenticationManager authenticationManager) throws Exception {  
        security
            .csrf(customizer -> customizer.disable())
            // 传递AuthenticationManager给过滤器
            .addFilterBefore(new CookieAuthenticationFilter(authenticationManager), BasicAuthenticationFilter.class)
            .authorizeHttpRequests(configurer -> configurer
                .requestMatchers("/*").authenticated()
                .anyRequest().permitAll())
            .sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        return security.build();
    }

}

优化UserAuthProvider的supports方法(可选但推荐)

将supports方法改为仅支持PreAuthenticatedAuthenticationToken,避免处理无关的认证类型:

@Override
public boolean supports(Class<?> authentication) {
    return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}

2. 是否可以在过滤器中解析路径变量?

可以,但存在限制:

  • Spring Security过滤器默认执行在DispatcherServlet之前,此时路径变量尚未被解析,无法直接通过request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)获取。
  • 如果需要在过滤器中获取路径变量,需将过滤器的执行顺序调整到DispatcherServlet之后,或者手动通过请求路径与匹配模式解析变量(实现复杂)。

更简便的方式是使用Spring MVC的拦截器(HandlerInterceptor),拦截器在DispatcherServlet处理请求后执行,此时路径变量已解析完成,可通过以下代码获取:

import org.springframework.web.servlet.HandlerMapping;

// 在拦截器的preHandle方法中
Map<String, String> pathVariables = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
String targetVar = pathVariables.get("varName");

3. 在拦截器层实现认证是否为良好实践?

不推荐,原因如下:

  • 覆盖范围有限:拦截器仅能处理Spring MVC请求,无法覆盖静态资源、非MVC Servlet请求等所有进入容器的请求,而过滤器可以处理全部请求。
  • 安全机制缺失:Spring Security过滤器链集成了CSRF防护、会话固定保护、安全上下文管理等成熟特性,在拦截器中实现认证需要自行处理这些细节,易出现安全漏洞。
  • 流程耦合:认证属于安全基础设施层逻辑,放在MVC拦截器中会导致安全逻辑与业务逻辑耦合,不符合分层设计原则。

建议认证逻辑仍放在Spring Security过滤器链中,若需在MVC层做权限校验,可使用Spring Security提供的@PreAuthorize、@PostAuthorize等注解,或自定义方法拦截器。


内容的提问来源于stack exchange,提问作者Anton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 17:32:01