Spring Security 3.4升级至5后角色权限验证异常问题
我之前也碰到过类似的版本升级权限坑,结合你的描述,大概率是这几个核心原因导致的,一步步来排查:
1. 优先检查URL Pattern是否匹配
你的实际请求URL是http://192.168.1.85:8087/api/readData/catlog/category?start=0&aid=all&db=xyz,但配置的拦截规则是:
<security:intercept-url method="GET" pattern="/readData/catlog/category/**" access="hasAnyRole('MasterAdmin','ManageCategories','ViewCategories')" />
这里的pattern少了/api前缀!Spring Security的拦截规则是严格匹配请求路径的,所以这条规则根本没命中你的请求,导致请求可能被其他默认的拦截规则(比如全局拒绝)挡住了。
解决方案:把pattern改成/api/readData/catlog/category/**,确保和实际请求路径完全对应。
2. 角色权限的前缀差异问题
Spring Security 5里的hasAnyRole()方法默认会自动给权限名加上ROLE_前缀,比如hasAnyRole('ManageCategories')实际会去验证用户是否拥有ROLE_ManageCategories权限。但你提到日志里显示用户拥有的是ManageCategories(不带前缀),这就直接导致匹配失败。
解决方案:
- 如果你不想修改权限存储的格式,直接把
hasAnyRole换成hasAnyAuthority就行,因为hasAnyAuthority会直接匹配权限字符串,不会自动添加前缀:<security:intercept-url method="GET" pattern="/api/readData/catlog/category/**" access="hasAnyAuthority('MasterAdmin','ManageCategories','ViewCategories')" /> - 要是你想继续用
hasAnyRole,也可以修改Spring Security的默认前缀配置,去掉自动添加的ROLE_:<security:http ...> <security:expression-handler ref="customWebSecurityExpressionHandler" /> <!-- 其他配置 --> </security:http> <bean id="customWebSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"> <property name="defaultRolePrefix" value="" /> </bean>
3. 拦截规则的顺序问题
Spring Security的intercept-url是按配置顺序匹配的,先匹配到的规则会优先生效。如果这条具体的规则前面有更宽泛的规则(比如pattern="/api/**" access="denyAll"),那请求会先被这条宽泛规则拦截,导致权限验证失败。
解决方案:把这个针对特定路径的拦截规则,放在所有宽泛规则的前面,确保它先被匹配到。
最后验证
修改完可以查看Spring Security的调试日志,找类似这样的记录:
Checking match of request : '/api/readData/catlog/category'; against '/api/readData/catlog/category/**'
确认规则已经成功匹配,同时查看权限验证的日志,确认用户的权限和规则要求的权限是否对应上。
内容的提问来源于stack exchange,提问作者Prashant Thorat

