给spring-security提了一个issue

栏目: Java · 发布时间: 5年前

内容简介:我在使用spring-security的角色继承,关键代码片段如下:上边关于角色继承的定义方式,是我在使用之前版本的spring-security获得经验,同时,通过spring-security源码的注释也可看到相关说明但是,当我实际跑起来后,发现根本不行,角色继承没生效。我就很纳闷了,原来用过spring-security啊,就是这样就可以啊。然后试了改了改权限表达式,结果还是不行,然后我想了想,调试源码吧,调试源码一般都是必杀技。在调试源码的过程中,我逐渐发现了问题所在。

今天在用spring-security的角色继承时,遇到了一个坑,通过调试源码解决了,然后发现这应该是spring-security本身的一个小问题,然后就在Spring官方的GitHub上提了一个 issue

给spring-security提了一个issue

正文

我在使用spring-security的角色继承,关键代码片段如下:

...
// 定义角色继承,两个角色继承之间用空格或and连接
roleHierarchyImpl.setHierarchy("ROLE_DEVELOPER > ROLE_SUPERVISOR and ROLE_SUPERVISOR > ROLE_ADMIN and ROLE_ADMIN > ROLE_USER and ROLE_USER > ROLE_ANONYMOUS");
...
...
// 定义需要的权限表达式
.access("hasRole('USER')")
...

上边关于角色继承的定义方式,是我在使用之前版本的spring-security获得经验,同时,通过spring-security源码的注释也可看到相关说明

/**
 * The simple interface of a role hierarchy.
 *
 * @author Michael Mayr
 */
public interface RoleHierarchy {

   /**
    * Returns an array of all reachable authorities.
    * <p>
    * Reachable authorities are the directly assigned authorities plus all authorities
    * that are (transitively) reachable from them in the role hierarchy.
    * <p>
    * Example:<br>
    * Role hierarchy: ROLE_A > ROLE_B and ROLE_B > ROLE_C.<br>
    * Directly assigned authority: ROLE_A.<br>
    * Reachable authorities: ROLE_A, ROLE_B, ROLE_C.
    *
    * @param authorities - List of the directly assigned authorities.
    * @return List of all reachable authorities given the assigned authorities.
    */
   public Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(
         Collection<? extends GrantedAuthority> authorities);

}

但是,当我实际跑起来后,发现根本不行,角色继承没生效。我就很纳闷了,原来用过spring-security啊,就是这样就可以啊。然后试了改了改权限表达式,结果还是不行,然后我想了想,调试源码吧,调试源码一般都是必杀技。在调试源码的过程中,我逐渐发现了问题所在。

我先给出角色表达式解析以及角色继承解析的相关代码路径,大家可按这个路径跟踪。

角色表达式解析:

// 由上到下为执行路径,最上端是入口点
org.springframework.security.web.FilterChainProxy.VirtualFilterChain#doFilter

org.springframework.security.web.access.intercept.FilterSecurityInterceptor#doFilter

org.springframework.security.access.intercept.AbstractSecurityInterceptor#beforeInvocation

org.springframework.security.web.access.intercept.FilterSecurityInterceptor#invoke

org.springframework.security.access.AccessDecisionManager#decide

org.springframework.security.access.vote.AffirmativeBased#decide

org.springframework.security.web.access.expression.WebExpressionVoter#vote

org.springframework.security.access.expression.ExpressionUtils#evaluateAsBoolean

org.springframework.expression.spel.standard.SpelExpression#getValue(org.springframework.expression.EvaluationContext, java.lang.Class<T>)

org.springframework.expression.spel.ast.SpelNodeImpl#getTypedValue

org.springframework.expression.spel.ast.MethodReference#getValueInternal(org.springframework.expression.spel.ExpressionState)

org.springframework.expression.spel.ast.MethodReference#getCachedExecutor

org.springframework.expression.spel.support.ReflectiveMethodExecutor#execute

java.lang.reflect.Method#invoke

org.springframework.security.access.expression.SecurityExpressionRoot#hasRole

org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole

org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyAuthorityName

注意上边执行路径中的 java.lang.reflect.Method#invoke 实际上,权限控制表达式内部的原理是是用反射去执行对应的用于判断是否有权限方法的,也就是执行 org.springframework.security.access.expression.SecurityExpressionRoot#hasRole

给spring-security提了一个issue

执行到下图中这里后,返回的是 false 也就是授权未通过,没有对应角色,当前拥有的角色是从 org.springframework.security.access.hierarchicalroles.RoleHierarchy#getReachableGrantedAuthorities 获得的,里面并没有需要的角色”ROLE”,因此自然就是 false

给spring-security提了一个issue

那么为什么没有呢,按照角色继承的定义,应该能够有才对啊,这是我们就需要看角色继承表达式生成具体角色的逻辑了,这个逻辑的代码路径是这个:

org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl#setHierarchy

org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl#buildRolesReachableInOneStepMap

org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl#buildRolesReachableInOneOrMoreStepsMap

通过跟踪这些代码,我们从中可以看出,实际上,正确的角色继承表达式应该这样定义:

...
roleHierarchyImpl.setHierarchy("ROLE_DEVELOPER > ROLE_SUPERVISOR > ROLE_ADMIN > ROLE_USER > ROLE_ANONYMOUS");
...

实际上定义角色继承表达式的规则已经变了,然而,在spring-security代码库中的 RoleHierarchy 这个类的注释,还保留着旧版的角色继承表达式的定义方式的说明,这应当是代码更新了但是注释未更新,我按照以往的经验以及注释的说明去写,结果掉坑里了。

总结

通过这次问题的排查,可以说明: 必要的注释可以有,但是不要过分依赖于注释,要相信代码本身 ,此外在这次调试源码的过程中我还发现了一个调试源码的技巧:利用 Drop Frame ,可以倒推代码的执行路径。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

新物种爆炸

新物种爆炸

吴声 / 中信出版社 / 2017-7-30 / 58.00元

宝马为什么要重点发展共享汽车 Airbnb正试图成为内容和社交平台 不排队、不结账、没有收银员的颠覆传统超市 茑屋书店要打造全新生活方式 基于新的商业环境与技术条件的变化,必须会产生新的品类和商业模式,这就是新物种! 大数据与人工智能等技术正在创建新的商业话语体系,创建新的权力架构,引领第四新物种爆炸。商业规则正在快速发生变化,新的模式与业态层出不穷。 要么成为......一起来看看 《新物种爆炸》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具