在网上看见很多的博客、技术文章,发现你们对于Spring Security中的角色(roles)存在较大的误解,最大的误解就是没有搞清楚其中角色和权限的差异(好多人在学习Spring Security时,是否是对于到底加不加“ROLE_”前缀有点犯蒙),有时候以为在进行权限控制时用权限名称或者用角色名称都差很少(你们这种感受是对的,若是简单应用确实差不太多)。
咱们在进行角色权限控制设计时,通常包括帐户(users)、角色(roles)、权限(authorities)这三部分。
1)一个帐户通常对应一个或多个角色;
2)一个角色对应多个权限(authorities),反过来一个权限也对应多个角色;
3)帐户只和角色关联,经过角色,间接和权限产生关系;
4)角色不是固定死的,是可以动态建立的,每一个角色具备的权限可以灵活的进行调整;
5)在系统完成详细设计后,有哪些权限就已经肯定下来,权限的层级结构和数量、与帐户和角色没半点关系。
基于以上的说明,咱们从源码的角度来讲明Spring Security的帐户、角色和权限是怎么一回事。
Spring Security工做流程:经过登陆的帐户,找到该帐户对应的角色/权限,并把自定义的权限集合转换为Spring Security承认的权限集合List<GrantedAuthority>,而后结合自定义的帐号、密码,和新权限集合这三个参数,建立一个Spring Security承认的帐号实例,再而后根据自定义的鉴权规则,进行权限控制。
这里面如何建立帐号、角色、权限,实现用户认证、进行鉴权的细节就不讲了,由于这个不是本篇文章的重点,有兴趣的读者能够看个人视频介绍:https://edu.51cto.com/sd/091c7 ,里面有详细的如何进行实战型的Spring Security角色权限控制模块的开发。
重点来了,经过应用角色权限控制的应用,看Spring Security如何利用角色和权限的
四种鉴权的方式:
hasRole(String role)
hasAnyRole(String... roles)
hasAuthority(String authority)
hasAnyAuthority(String... authorities)
在源码类SecurityExpressionRoot.java中,咱们看看这四种方式的实现形式:
你们从上面的图看出什么端倪没有?
hasRole(String role) --》 hasAnyRole(String... roles) --》hasAnyAuthorityName
hasAuthority(String authority) --》hasAnyAuthority(String... authorities) --》hasAnyAuthorityName
不论是基于角色,仍是基于权限,最后鉴权都落实到hasAnyAuthorityName这个方法上。 java
follow me,咱们继续往下刨根,看看hasAnyAuthorityName这个方法里面有些什么,注意上面代码中的调用hasAnyAuthorityName时,传递的参数,一个是
另一个是
对应的都是一个实现方法。 数据库
从hasAnyAuthorityName这个方法中,咱们能够知道,这是把传进去的一个或多个角色/权限,在登陆用户具备的权限中进行查找
这里面的你们看到了吧,角色和权限是混合在一块儿进行鉴权的(题外话,你们看大神们写的代码,注意到其中的var五、var六、var4,这是搞什么?严重不符合命名规范啊)。
那么Spring Security是如何区分集合中的是权限、仍是角色呢,咱们继续抽丝剥茧,看看该方法中的getRoleWithDefaultPrefix(prefix, role)方法
看上面的代码清晰明了了吧,说明以下:
若是传进去的角色名称/权限名称为null,直接返回null;
若是传进去的角色名称/权限名称不为null,则判断defaultRolePrefix前缀这个参数是否为空和其长度,若是不为空,且长度不为0,则传进的参数为角色名称,那么继续判断其是不是以“ROLE”开始,若是不是,则在名称前添加前缀“ROLE”,并返回新的名称;
若是不是以上状况,即参数是权限名称或者带有“ROLE_”前缀的角色名称,直接返回传进去的字符串参数。ide
看了以上Spring Security的部分源码解析,咱们能够得出什么结论呢(以角色、权限存放在数据库为例):
一、原生的角色和权限并无本质的区别,在鉴权时走的是彻底相同的一个通道;
二、在进行权限控制时,角色可加可不加“ROLE”前缀,但在数据库中定义时,角色名称必定要添加“ROLE”前缀;
三、角色与权限之间并无创建映射关系,角色是角色、权限是权限,这与咱们实际应用中对角色的要求有很大出入;
四、实际应用中的角色被固化到代码中,也与实际要求不符,实际应用中,权限做为子节点能够写死,而角色做为所有或者部分权限的集合应该能够灵活调整;
五、不论是角色鉴权,仍是权限鉴权,都只是以角色/权限的名称做为判断依据,因此权限的名称要惟一。
另外,从Spring Security的源码分析中能够发现,咱们还能够经过RoleHierarchy进行角色的继承(默认admin登陆只能访问/admin,访问不了/user;而user登陆只能访问/user),但在实际项目中,最主要强调的是角色的灵活性,而不是继承性。
因此,对角色的管理、角色和权限的映射关系,都须要咱们本身来实现。
好了,对Spring Security角色(roles)的分析就到此结束,从以上分析看,咱们若是要把Spring Security应用于实际项目中,还须要作很多工做,至于如何简洁高效的利用Spring Security进行角色权限控制模块的开发,有兴趣的读者能够看个人视频介绍:https://edu.51cto.com/sd/091c7 ,但愿对你们有有所帮助。源码分析