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

Spring Security 5.5.7升级后登录认证成功却遇会话超时/权限拒绝

升级Spring Security 5.5.7后认证成功却触发权限拒绝的问题解决

问题背景

将Spring及Spring Security升级至5.5.7版本后,输入有效凭据完成认证后,系统提示会话超时并重定向至“您无权访问此页面”的权限拒绝页面,升级前功能正常。

相关代码片段

login.jsp

<form role="form" id="loginForm" action="<c:url value="/j_spring_security_check" ></c:url>" method="post">

spring-security.xml

<security:http auto-config="true" use-expressions="true"
            create-session="ifRequired" authentication-manager-ref="authenticationManager" >

            <security:form-login login-page="/login-fail?error"
                    default-target-url="/home" authentication-failure-url="/login-fail?error"
                    username-parameter="username" password-parameter="password" login-processing-url="/j_spring_security_check" />

             <security:logout invalidate-session="true"
                    logout-success-url="/logout?logout" logout-url="/j_spring_security_logout"
                    delete-cookies="JSESSIONID" />

            <security:session-management invalid-session-url="/login-fail?error-timeout"
                    session-fixation-protection="migrateSession">
                    <security:concurrency-control
                            max-sessions="50" error-if-maximum-exceeded="false"
                            expired-url="/login-fail?error-timeout" />
            </security:session-management>

            <security:remember-me
            token-validity-seconds="3600"
            remember-me-parameter="remember"
            data-source-ref="dataSource"
            />

            <security:headers>
                    <security:frame-options policy="SAMEORIGIN" />
            </security:headers>
</security:http>

Home Controller核心代码

@SuppressWarnings("deprecation")
@PreAuthorize("hasAnyRole('HOME')")
@RequestMapping(value = { ControllerConstants.HOME,ControllerConstants.SSOHOME }, method = RequestMethod.GET)
public ModelAndView home(@RequestParam(value = "isRsaSuccess", required=false) String isRsaSuccess,HttpServletRequest request)  throws StaffUniqueContraintException,SMException{
    ModelAndView model = new ModelAndView();
    if(isRsaSuccess==null)
        isRsaSuccess="no";
    User springUserBeanHome = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    
    // 剩余业务逻辑...
}

错误日志

[ DEBUG ][ 27 Sep 2022 11:57:20,302 ] [ AspectControllerLogging ] : Arguments passed: [org.springframework.security.access.AccessDeniedException: Access is denied, SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@18f8cbc0], org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterResponse@7e4fc76a, en]
[ ERROR ][ 27 Sep 2022 11:57:20,307 ] [ ExceptionHandlingController ] : Access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.5.7.jar:5.5.7]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238) ~[spring-security-core-5.5.7.jar:5.5.7]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208) ~[spring-security-core-5.5.7.jar:5.5.7]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:58) ~[spring-security-core-5.5.7.jar:5.5.7]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar:5.3.20]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar:5.3.20]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.20.jar:5.3.20]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar:5.3.20]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar:5.3.20]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar:5.3.20]
    at com.elitecore.sm.iam.controller.HomeController$$EnhancerBySpringCGLIB$$a8dbedab.home(<generated>) ~[classes/:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.20.jar:5.3.20]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.20.jar:5.3.20]

问题根源

Spring Security 5.x版本中,hasAnyRole()表达式会自动为传入的角色名添加ROLE_前缀进行匹配。如果你的用户权限列表中仅存在HOME(而非ROLE_HOME),就会导致权限校验失败,触发AccessDeniedException。

旧版本可能存在配置差异,或者权限加载逻辑未适配5.x的这一默认规则。

验证步骤

在HomeController的home方法开头添加日志,打印当前用户的权限集合,确认权限格式:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("当前用户权限列表: " + auth.getAuthorities());

若输出为[HOME]而非[ROLE_HOME],即可确认是前缀匹配问题。

解决方案

方案1:替换表达式为hasAnyAuthority()

hasAnyAuthority()不会自动添加前缀,直接匹配原始权限字符串,修改注解:

@PreAuthorize("hasAnyAuthority('HOME')")

方案2:调整权限加载逻辑,添加ROLE_前缀

在用户认证流程中,为角色名统一添加ROLE_前缀。例如在UserDetailsService实现类中:

List<GrantedAuthority> authorities = new ArrayList<>();
// roles为从数据源获取的角色列表,如["HOME"]
for (String role : roles) {
    authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}

方案3:关闭默认角色前缀(不推荐)

若不想修改业务代码,可通过配置关闭自动添加前缀的行为,但会改变Spring Security默认规则,可能影响其他权限校验:

<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="methodSecurityExpressionHandler"/>
</security:global-method-security>

<bean id="methodSecurityExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="defaultRolePrefix" value=""/>
</bean>

额外排查点

  • 确认session-fixation-protection="migrateSession"配置在升级后正常工作,认证后会话中的用户权限信息是否正确迁移。
  • 临时关闭remember-me功能,排查是否是记住我逻辑干扰了权限加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:26:19