Spring Security 4.1 升级 - 错误 403 访问被拒绝

Posted

技术标签:

【中文标题】Spring Security 4.1 升级 - 错误 403 访问被拒绝【英文标题】:Spring Security 4.1 upgrade - Error 403 Access Denied 【发布时间】:2017-01-10 11:30:50 【问题描述】:

我在升级到 Spring Security 4.1.2 和 Spring 4.3.2 时收到 403 Access Denied Error code

Spring-Security.xml 文件

    ...
<spring:bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
</spring:bean>

<spring:bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter"/>

<spring:bean id="webExpressionVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter" />

<spring:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
      <spring:constructor-arg>
       <spring:list>
            <spring:ref bean="roleVoter"/>
            <spring:ref bean="authenticatedVoter"/>
            <spring:ref bean="webExpressionVoter"/>
        </spring:list>
  </spring:constructor-arg>
</spring:bean>

<security:http access-decision-manager-ref="accessDecisionManager" auto-config='true' use-expressions="true">

    <security:intercept-url pattern="/login.jsp" access="hasRole('ROLE_ANONYMOUS')" />
    <security:intercept-url pattern="/j_spring_security_check" access="hasRole('ROLE_ANONYMOUS')" />

    <security:intercept-url pattern="/index*" access="hasRole('ROLE_USER')"/>

    <security:form-login login-page="/login.jsp"
        username-parameter="j_username"
        password-parameter="j_password"
        login-processing-url="/j_spring_security_check"
        authentication-failure-url="/accessDenied.jsp" />

    <security:logout invalidate-session="true"  delete-cookies="JSESSIONID"/>

    <security:csrf disabled="true"/>

</security:http>
...

我正在使用 Spring Security AuthenticationProvider 类进行身份验证。类中的authenticate(Authentication authentication)方法执行成功,返回新的UsernamePasswordAuthenticationToken(user, pwd, authority)。

错误堆栈跟踪:

2016-09-02 14:59:21,461 DEBUG [http-/127.0.0.1:8080-1] [org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:66)] - Voter: org.springframework.security.access.vote.RoleVoter@52989292, returned: 0
2016-09-02 14:59:21,461 DEBUG [http-/127.0.0.1:8080-1] [org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:66)] - Voter: org.springframework.security.access.vote.AuthenticatedVoter@203cc7cd, returned: 0
2016-09-02 14:59:21,461 DEBUG [http-/127.0.0.1:8080-1] [org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:66)] - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@5e01cc46, returned: -1
2016-09-02 14:59:21,462 DEBUG [http-/127.0.0.1:8080-1] [org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:362)] - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /index.html]
2016-09-02 14:59:21,462 DEBUG [http-/127.0.0.1:8080-1] [org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:186)] - Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)

从错误堆栈跟踪中,WebExpressionVoter 返回 -1。

【问题讨论】:

在 Spring Security 4.1 迁移之前,WebExpressionVoter 没有添加到 AffirmativeBased 决策管理器中。但是,在 4.1 中,似乎必须添加 WebExpressionVoter。而且,这个选民返回 -1。 另外,为什么错误堆栈跟踪的下面一行说“不是匿名的”? - 访问被拒绝(用户不是匿名的) 【参考方案1】:

spring安全文件中将hasRole替换为hasAuthority后解决。

【讨论】:

【参考方案2】:

如果我们在很多地方都使用hasAnyRolehasRole,那么用hasAuthority 替换所有都是不可行的。这是 Spring 中一个非常令人困惑的升级。如果我们想使用与 Spring 3 相同的角色名称,我们需要附加 ROLE_ 角色名称。例如,如果您使用的是 APP_ADMIN,如果登录用户具有角色 APP_ADMIN,则 Spring 3 将评估 hasRole(APP_ADMIN) 为 true。为了在 Spring 4 中进行同样的操作,您需要将角色更改为 ROLE_APP_ADMIN 以使 hasRole(APP_ADMIN) 为真。

除了制造混乱之外,这根本没有任何意义,无论“创作者”给出的解释是什么

【讨论】:

以上是关于Spring Security 4.1 升级 - 错误 403 访问被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

spring security3.1升级到4.1问题访问/j_spring_security_check 404

将 Spring Boot 升级到 2.4.1

Spring Boot 和 Spring Cloud Security OAUTH 2 SSO 在最新版本中失败

Spring Boot /h2-console 使用 Spring Security 1.5.2 抛出 403

从 stark-security 升级到 spring 安全插件

spring boot 整合spring security中spring security版本升级的遇到的坑