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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:59:53