Spring Security SAML2登录成功后如何仅执行一次过滤器/处理器?
针对你的需求,有两种可靠的实现方式,都能确保仅在SAML2登录成功时触发一次Cookie设置逻辑:
方案一:使用认证成功事件监听器
Spring Security会在认证成功时发布AuthenticationSuccessEvent事件,我们可以监听这个事件,并判断是否为SAML2认证,再执行Cookie设置逻辑:
1. 实现事件监听器
@Component public class Saml2LoginSuccessListener implements ApplicationListener<AuthenticationSuccessEvent> { @Override public void onApplicationEvent(AuthenticationSuccessEvent event) { Authentication authentication = event.getAuthentication(); // 仅处理SAML2认证成功的情况 if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { // 获取当前请求响应 HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); if (response != null) { // 自定义Cookie逻辑 Cookie customCookie = new Cookie("custom-token", "your-generated-token"); customCookie.setPath("/"); // 按需配置Cookie属性:HttpOnly、Secure等 customCookie.setHttpOnly(true); customCookie.setSecure(true); response.addCookie(customCookie); } } } }
说明
- 该监听器仅在认证成功时触发一次,不会在后续请求中重复执行
- 通过
Saml2AuthenticatedPrincipal判断是否为SAML2登录,避免处理其他认证方式的成功事件 - Spring Web环境默认支持通过
RequestContextHolder获取当前请求上下文
方案二:自定义SAML2登录成功处理器
直接配置Spring Security的SAML2登录专属成功处理器,这是更精准的方式,仅针对SAML2登录流程:
1. 自定义登录成功处理器
@Component public class CustomSaml2AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // 仅处理SAML2认证 if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { // 设置自定义Cookie Cookie customCookie = new Cookie("custom-token", "your-generated-token"); customCookie.setPath("/"); customCookie.setHttpOnly(true); customCookie.setSecure(true); response.addCookie(customCookie); } // 调用父类方法,保留默认跳转逻辑(比如跳转到登录前的受保护页面) super.onAuthenticationSuccess(request, response, authentication); } }
2. 在Security配置中绑定处理器
修改你的SAMLConfiguration配置类,将自定义处理器配置到saml2Login流程中:
@Configuration public class SAMLConfiguration { @Autowired private CustomSaml2AuthenticationSuccessHandler saml2SuccessHandler; @Bean SecurityFilterChain configure(HttpSecurity http) throws Exception { OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider(); Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationRepository, new OpenSamlMetadataResolver()); http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class); http.authorizeHttpRequests(requests -> requests .requestMatchers("/saml2/service-provider-metadata/**") .permitAll() ).saml2Login(saml2 -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) .relyingPartyRegistrationRepository(relyingPartyRegistrationRepository) // 绑定自定义成功处理器 .successHandler(saml2SuccessHandler) ).saml2Logout(withDefaults()); } }
说明
- 该处理器是SAML2登录流程的专属回调,只会在SAML2登录成功时执行一次
- 继承
SavedRequestAwareAuthenticationSuccessHandler可以保留默认的跳转逻辑,若不需要可直接实现AuthenticationSuccessHandler接口
为什么之前的方案失效?
- SetToken过滤器:你将它添加到了全局过滤器链中,所有请求都会经过该过滤器,无法实现仅登录时执行的逻辑
- SessionAuthenticationStrategy:当设置
SessionCreationPolicy.STATELESS时,Spring Security不会创建会话,每次请求都会重新触发认证逻辑;即使是有状态会话,该策略也会在会话重新认证时触发,不符合仅执行一次的需求
内容的提问来源于stack exchange,提问作者Sumeet Kumar Yadav
相关产品推荐
相关产品推荐

