Spring Security认证后重定向失效问题排查求助
Spring Security 5 外部用户认证后重定向失效问题
问题描述
原本基于Spring 3实现的外部用户限权认证访问机制,升级到Spring 5后出现异常:用户完成认证后无法重定向到指定页面(/xhtml/web.xhtml),执行过程无报错,但页面停留在原访问路径/externalAccess?username=&password=&...。
相关代码
认证处理Servlet代码
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { externalSession = false; try { String appUrl = ConstantesAplicacion.PROTOCOL + request.getServerName() + ":" + request.getLocalPort() + request.getContextPath(); String user = null; String password = null; /** 提取并处理请求其他参数的代码 **/ if (correct_parameters) { DigitalizaAuthenticationProcessingFilter filter = (DigitalizaAuthenticationProcessingFilter) NavigationUtilities.getJSFBean("paramAuthenticationProcessingFilter"); SimpleUrlAuthenticationSuccessHandler success = new SimpleUrlAuthenticationSuccessHandler(); if (clinicalHistoryService.existsHistory(null, null, cip)) { if (DataUtilities.isNotEmpty(cip)) { String aux = "/xhtml/web.xhtml"; auxParameters = "&fullName=" + fullName + "&username=" + user + "&code=" + cid + "&ExternalAccess=True&Profile=" + profile + "&random=" + Math.random()*100000; if (episode != null && !"".equals(episode)){ auxParameters = auxParameters + "&episode=" + episode; } success.setDefaultTargetUrl(aux); } } else { success.setDefaultTargetUrl("/xhtml/web2.xhtml?searchErrorExt=1"); } if(!externalSession){ filter.setAuthenticationSuccessHandler(success); response.sendRedirect(appUrl + "/j_spring_security_check?j_username=" + user + "&j_password=" + password + "" + auxParameters); } else { response.sendRedirect(appUrl + "/xhtml/web.xhtml"); } } else { LOG.error("invalid ip"); throw new DigitalizaAppException(); } } catch (Exception e) { throw new DigitalizaAppException(e); } }
Spring Security配置文件(applicationContext-security.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <global-method-security secured-annotations="enabled" /> <http use-expressions="true" auto-config="true" > <access-denied-handler error-page="/denied"/> <intercept-url pattern="/xhtml/errors/**" access="permitAll" /> <intercept-url pattern="/j_spring_security_check" access="permitAll"/> <intercept-url pattern="/index.xhtml" access="isAuthenticated()" /> <custom-filter ref="paramAuthenticationProcessingFilter" position="PRE_AUTH_FILTER"/> <custom-filter ref="exceptionTranslationFilter" before="FILTER_SECURITY_INTERCEPTOR" /> <form-login login-page="/inicio.xhtml" default-target-url="/xhtml/search/searchHistory.xhtml" username-parameter="username" password-parameter="password" login-processing-url="/j_spring_security_check" authentication-failure-url="/inicio.xhtml?error_page=1" /> <logout invalidate-session="true" logout-url="/j_spring_security_logout" logout-success-url="/inicio.xhtml"/> <csrf disabled="true"/> <headers> <frame-options policy="SAMEORIGIN" /> </headers> </http> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="userDetailsService"> <password-encoder ref="passwordEncoder" /> </authentication-provider> </authentication-manager> <beans:bean id="passwordEncoder" class="es.organization.proyecto.infrastructure.encryption.DIGEncryption"/> <beans:bean id="userDetailsService" class="es.organization.proyecto.infrastructure.security.impl.UserDetailsServiceImpl"/> <beans:bean id="paramAuthenticationProcessingFilter" class="es.organization.proyecto.infrastructure.security.impl.proyectoAuthenticationProcessingFilter"> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="authenticationSuccessHandler"> <beans:bean id="successHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/xhtml/web2.xhtml" /> </beans:bean> </beans:property> <beans:property name="AuthenticationFailureHandler"> <beans:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/inicio.xhtml?error_page=1" /> </beans:bean> </beans:property> </beans:bean> <!-- Automatically receives AuthenticationEvent messages --> <beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener" /> <beans:bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/> <beans:bean id="authenticationEntryPoint" class="es.organization.proyecto.infrastructure.security.JsfLoginUrlAuthenticationEntryPoint"> <beans:property name="loginFormUrl" value="/inicio.xhtml"/> <beans:property name="redirectStrategy" ref="jsfRedirectStrategy" /> </beans:bean > <beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <beans:constructor-arg ref="authenticationEntryPoint"/> <!-- Constructor --> <beans:property name="accessDeniedHandler" ref="jsfAccessDeniedHandler"/> </beans:bean> <beans:bean id="jsfAccessDeniedHandler" class="es.organization.proyecto.infrastructure.security.JsfAccessDeniedHandler"> <beans:property name="loginPath" value="/errors/accessDenied.xhtml" /> </beans:bean> <!-- Bean for managing the security redirection strategy --> <beans:bean id="jsfRedirectStrategy" class="es.organization.proyecto.infrastructure.security.JsfRedirectStrategy"/> </beans:beans>
已完成的排查步骤
- 确认
/xhtml/web.xhtml路径存在且书写正确; - 分步调试未发现代码执行异常;
- 检查应用日志未找到相关报错信息;
- 验证Spring Security配置无明显语法或逻辑错误。
排查方向与解决建议
1. 过滤器顺序与优先级问题
Spring 5对过滤器链的执行顺序做了更严格的约束,PRE_AUTH_FILTER的位置可能与默认的UsernamePasswordAuthenticationFilter冲突。建议:
- 移除
auto-config="true",手动配置所需过滤器,避免自动注册的过滤器干扰自定义逻辑; - 调整自定义过滤器的位置,改为
position="FORM_LOGIN_FILTER",确保在表单认证过滤器之前执行,或者明确指定过滤器的顺序值。
2. 认证成功处理器的设置有效性
当前代码中动态设置SimpleUrlAuthenticationSuccessHandler的方式在Spring 5中可能因Bean的单例特性失效:
- 由于
paramAuthenticationProcessingFilter是单例Bean,动态替换successHandler会导致并发场景下的冲突,建议改为在SuccessHandler中动态判断跳转目标,而非替换整个Handler实例; - 实现自定义的
AuthenticationSuccessHandler,在onAuthenticationSuccess方法中根据请求参数(如ExternalAccess)动态计算跳转路径,而非在外部设置默认URL。
3. 重定向请求的处理逻辑
Spring 5对sendRedirect的处理与Spring 3存在差异,尤其是在会话管理和响应头设置上:
- 检查
response.sendRedirect执行前是否已提交响应,若响应已提交则重定向无效; - 尝试使用Spring Security提供的
RedirectStrategy(如配置中的jsfRedirectStrategy)执行重定向,而非直接调用response.sendRedirect,确保符合Spring Security的响应处理规范; - 注意重定向URL中的参数是否需要编码,避免因特殊字符导致重定向失效(比如
fullName包含空格或特殊字符时,需要用URLEncoder.encode处理)。
4. 会话与SecurityContext的存储
Spring 5默认的SecurityContextRepository行为有变化,可能导致认证信息未正确存储:
- 确保
paramAuthenticationProcessingFilter正确设置了securityContextRepository属性,指定为配置中的httpSessionSecurityContextRepository; - 调试时检查
SecurityContextHolder在认证后是否包含正确的认证对象,确认认证流程是否真正完成。
5. 自定义过滤器的兼容性
DigitalizaAuthenticationProcessingFilter继承的父类在Spring 5中可能有API变更:
- 检查该自定义过滤器是否正确实现了Spring 5的
AuthenticationFilter接口或继承了正确的父类(如AbstractAuthenticationProcessingFilter); - 确保过滤器的
attemptAuthentication方法正确处理请求,并返回有效的Authentication对象,且successfulAuthentication方法正确调用SuccessHandler。
内容的提问来源于stack exchange,提问作者Amalio
相关产品推荐
相关产品推荐

