M 目前正在致力于将应用程序迁移到 JDK 17、Jakarta EE 9、Apache Tomcat 10.1 和 Spring Framework 6.0。作为此迁移的一部分,Spring Security 框架已迁移到 6.1.4。完成必要的代码和配置更改后,Tomcat应用程序服务器启动成功,并且也能够登录应用程序。但是,当我尝试从应用程序内访问特定网页时,它会给出 403 的 HTTP 响应。
以下是进一步分析问题后得到的一些细节。这是一个具有以下 URL 的 GET 请求:
我检查了 Spring Security 配置文件 (applicationContext-security.xml) 并观察到此网页的安全配置如下:
<security:intercept-url pattern="/pages/client/**"
access="hasAnyRole('BROKERPERSON, BROKERPERSONVIEW, PROCESSOWNER')" />
以下是 Spring Security 配置文件的片段,其中配置了不同页面的角色:
<security:http auto-config="true" use-expressions="true" disable-url-rewriting="true">
<security:form-login login-page="/pages/login.jsf"/>
<security:custom-filter position="PRE_AUTH_FILTER"
ref="preAuthFilter" />
<security:intercept-url pattern="/pages/client/**"
access="hasAnyRole('BROKERPERSON, BROKERPERSONVIEW, PROCESSOWNER')" />
<security:intercept-url pattern="/pages/contacts/**"
access="hasAnyRole('BROKERPERSON, COMPANYADMIN, BRANCHADMIN, PROCESSOWNER, ACCOUNTANT, PREMIUMFUNDINGUSER, SYSTEM')" />
<security:intercept-url pattern="/pages/report/**"
access="permitAll" />
<security:intercept-url pattern="/pages/home/**"
access="permitAll" />
<security:intercept-url pattern="/**/*.jsf" access="permitAll" />
<security:intercept-url pattern="/**/*.gif" access="permitAll" />
<security:intercept-url pattern="/**/*.js" access="permitAll" />
<security:intercept-url pattern="/pages/security/password_update.jsf"
access="hasAnyRole('ROLE_ANONYMOUS, BROKERPERSON, COMPANYADMIN, BRANCHADMIN, PROCESSOWNER, ACCOUNTANT, PREMIUMFUNDINGUSER, SYSTEM')" />
<security:csrf disabled="true"/>
<security:headers >
<security:frame-options policy="SAMEORIGIN" />
<security:hsts disabled="true"/>
<security:content-type-options disabled="true"/>
<security:xss-protection disabled="true"/>
<security:cache-control disabled="true"/>
</security:headers>
</security:http>
<!-- User Context bean defined as session scope using aop scoped proxy -->
<bean id="userContext" class="com.swift.core.security.view.UserContext"
scope="session">
<aop:scoped-proxy proxy-target-class="true" />
</bean>
<!-- List of request handler(s) beans -->
<bean id="verifyUserHandler"
class="com.swift.core.security.common.handlers.VerifyUserRequestHandler" />
<bean id="userAuthHandler"
class="com.swift.core.security.common.handlers.UserAuthenticationRequestHandler" />
<bean id="userAuthDummyHandler"
class="com.swift.core.security.common.handlers.UserAuthenticationRequestDummyHandler" />
<bean id="userParamHandler"
class="com.swift.core.security.common.handlers.UserParameterRequestHandler" />
<bean id="userWebSecurityExpressionHandler"
class="com.swift.core.security.common.handlers.UserWebSecurityExpressionHandler" />
<bean id="preAuthFilter" class="com.swift.core.security.filter.SwiftPreAuthFilter">
<property name="checkForPrincipalChanges">
<value>true</value>
</property>
<property name="handlers">
<!-- List of request handler(s) -->
<list>
<ref bean="verifyUserHandler" />
<ref bean="userAuthHandler" />
<!--
<ref bean="userAuthDummyHandler" />
-->
<ref bean="userParamHandler" />
<ref bean="userWebSecurityExpressionHandler" />
</list>
</property>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="preAuthUserDetailsService" />
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="preauthAuthProvider">
</security:authentication-provider>
</security:authentication-manager>
进一步调试 java 代码时观察到,在尝试访问此页面时,用户上下文的角色为 BROKERPERSON 和 PROCESSOWNER,权限为 ROLE_BROKERPERSON 和 ROLE_PROCESSOWNER。因此,根据我的分析,当尝试访问该页面时,后端代码具有所需的用户角色和权限,但仍然观察到 403 响应代码。仅针对访问提到特定角色的 url 模式观察到此问题。对于所有访问权限为 permitAll 的 URL,其工作正常。此外,相同的代码在旧版本(即 JDK 8、Apache Tomcat 8.5、Spring Framework 4.2.x 和 Spring Security 4.0.x)中可以正常工作。
作为解决方法,我已将突出显示的配置从 hasAnyRole 更改为 hasRole,如下所示:
<security:intercept-url pattern="/pages/client/**"
access="hasRole('BROKERPERSON')" />
<security:intercept-url pattern="/pages/client/**"
access="hasRole('BROKERPERSONVIEW')" />
<security:intercept-url pattern="/pages/client/**"
access="hasRole('PROCESSOWNER')" />
此更改后,网页按预期正常工作,并且没有观察到 403 响应代码。但是,问题仍然是,为什么使用 hasAnyRole 时会获得 403 响应代码。我试图在技术论坛上找到答案,但之前没有看到此类问题的报告。请告诉我是否有人以前遇到过类似的问题以及解决该问题所采取的步骤?
考虑使用
hasAnyRole('BROKERPERSON', 'BROKERPERSONVIEW', 'PROCESSOWNER')
。确保每个角色都用逗号分隔。
有关更多详细信息,请参阅文档https://docs.spring.io/spring-security/reference/5.7/servlet/authorization/expression-based.html。