Spring-SAML认证成功后陷入无限重定向循环问题咨询
我之前确实碰到过一模一样的场景!这种问题本质上是Spring Security过滤器链的执行逻辑或Provider匹配规则出了问题——SAML认证成功后,BasicAuthenticationFilter还在试图执行认证流程,而SAMLAuthenticationProvider根本不处理UsernamePasswordAuthenticationToken,抛出的异常会触发系统的重定向逻辑,最终形成无限循环。
给你几个经过验证的解决思路:
1. 让BasicAuthenticationFilter仅对未认证请求生效
你可以通过自定义过滤器逻辑,让Basic认证只在用户未被认证时触发,避免干扰已完成SAML认证的请求:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .saml2Login() // 保留你的SAML登录配置 .and() .addFilterBefore(new BasicAuthenticationFilter(authenticationManager()) { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { // 已认证则直接跳过Basic认证流程 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) { chain.doFilter(request, response); return; } super.doFilterInternal(request, response, chain); } }, UsernamePasswordAuthenticationFilter.class); }
2. 为AuthenticationManager配置Provider匹配规则
问题的核心是AuthenticationManager错误地把UsernamePasswordAuthenticationToken交给了SAMLAuthenticationProvider处理。你可以为不同的Token类型绑定专属Provider,避免交叉调用:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置Basic认证专属的Provider DaoAuthenticationProvider basicAuthProvider = new DaoAuthenticationProvider(); basicAuthProvider.setUserDetailsService(userDetailsService); basicAuthProvider.setPasswordEncoder(passwordEncoder); // 配置SAML认证Provider SAMLAuthenticationProvider samlAuthProvider = new SAMLAuthenticationProvider(); // 这里添加你的SAML Provider配置(比如用户信息映射等) // 让AuthenticationManager根据Token类型匹配对应的Provider auth.authenticationProvider(basicAuthProvider) .authenticationProvider(samlAuthProvider); }
Spring Security的ProviderManager会自动根据Token的类型选择合适的Provider,不会再把Basic认证的Token传给SAMLProvider。
3. 直接禁用不必要的BasicAuthenticationFilter
如果你的系统根本不需要Basic认证方式,这是最直接的解决方案:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .saml2Login() .and() .httpBasic().disable(); // 彻底禁用Basic认证过滤器 }
另外,你可以顺便检查下SecurityContext的持久化状态——有时候SAML认证成功后,SecurityContext没有被正确存入Session,导致后续请求被判定为未认证,再次触发Basic认证逻辑。可以通过调试SecurityContextHolder.getContext()在认证前后的状态来确认。
内容的提问来源于stack exchange,提问作者JavaHead

