五:Spring Security 中的角色继承问题
SpringSecurity 在角色继承上有两种不同的写法,在 Spring Boot2.0.8(对应 Spring Security 也是 5.0.11)上面是一种写法,从 Spring Boot2.1.0(对应 Spring Security5.1.1)又是另外一种写法。
以前的写法
这里说的以前写法,就是指 SpringBoot2.0.8(含)之前的写法,在之前的写法中,角色继承只需要开发者提供一个 RoleHierarchy 接口的实例即可,例如下面这样:
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy = "ROLE_dba > ROLE_admin ROLE_admin > ROLE_user";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
在这里我们提供了一个 RoleHierarchy 接口的实例,使用字符串来描述了角色之间的继承关系, ROLE_dba 具备 ROLE_admin 的所有权限,而 ROLE_admin 则具备 ROLE_user 的所有权限,继承与继承之间用一个空格隔开。提供了这个 Bean 之后,以后所有具备 ROLE_user 角色才能访问的资源, ROLE_dba 和 ROLE_admin 也都能访问,具备 ROLE_amdin 角色才能访问的资源, ROLE_dba 也能访问。
现在的写法
但是上面这种写法仅限于 Spring Boot2.0.8(含)之前的版本,在之后的版本中,这种写法则不被支持,新版的写法是下面这样:
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy = "ROLE_dba > ROLE_admin \n ROLE_admin > ROLE_user";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
变化主要就是分隔符,将原来用空格隔开的地方,现在用换行符了。
上面两种不同写法都是配置角色的继承关系,配置完成后,接下来指定角色和资源的对应关系即可,如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**")
.hasRole("admin")
.antMatchers("/db/**")
.hasRole("dba")
.antMatchers("/user/**")
.hasRole("user")
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
.csrf().disable();
}
这个表示/db/** 格式的路径需要具备 dba 角色才能访问,/admin/**格式的路径则需要具备 admin 角色才能访问, /user/** 格式的路径,则需要具备 user 角色才能访问,此时提供相关接口,会发现,dba 除了访问/db/** ,也能访问 /admin/** 和 /user/** ,admin 角色除了访问/admin/**,也能访问 /user/** ,user 角色则只能访问 /user/**。
源码分析
这样两种不同的写法,其实也对应了两种不同的解析策略,角色继承关系的解析在 RoleHierarchyImpl 类的 buildRolesReachableInOneStepMap 方法中,Spring Boot2.0.8(含)之前该方法的源码如下:
private void buildRolesReachableInOneStepMap() {
Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*>\\s*([^\\s>]+))");
Matcher roleHierarchyMatcher = pattern
.matcher(this.roleHierarchyStringRepresentation);
this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
while (roleHierarchyMatcher.find()) {
GrantedAuthority higherRole = new SimpleGrantedAuthority(
roleHierarchyMatcher.group(2));
GrantedAuthority lowerRole = new SimpleGrantedAuthority(
roleHierarchyMatcher.group(3));
Set<GrantedAuthority> rolesReachableInOneStepSet;
if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
rolesReachableInOneStepSet = new HashSet<>();
this.rolesReachableInOneStepMap.put(higherRole,
rolesReachableInOneStepSet);
}
else {
rolesReachableInOneStepSet = this.rolesReachableInOneStepMap
.get(higherRole);
}
addReachableRoles(rolesReachableInOneStepSet, lowerRole);
logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
+ " one can reach role " + lowerRole + " in one step.");
}
}
从这段源码中我们可以看到,角色的继承关系是通过正则表达式进行解析,通过空格进行切分,然后构建相应的 map 出来。
Spring Boot2.1.0(含)之后该方法的源码如下:
private void buildRolesReachableInOneStepMap() {
this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
try (BufferedReader bufferedReader = new BufferedReader(
new StringReader(this.roleHierarchyStringRepresentation))) {
for (String readLine; (readLine = bufferedReader.readLine()) != null;) {
String[] roles = readLine.split(" > ");
for (int i = 1; i < roles.length; i++) {
GrantedAuthority higherRole = new SimpleGrantedAuthority(
roles[i - 1].replaceAll("^\\s+|\\s+$", ""));
GrantedAuthority lowerRole = new SimpleGrantedAuthority(roles[i].replaceAll("^\\s+|\\s+$
Set<GrantedAuthority> rolesReachableInOneStepSet;
if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
rolesReachableInOneStepSet = new HashSet<GrantedAuthority>();
this.rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
} else {
rolesReachableInOneStepSet = this.rolesReachableInOneStepMap.get(higherRole);
}
addReachableRoles(rolesReachableInOneStepSet, lowerRole);
if (logger.isDebugEnabled()) {
logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
+ " one can reach role " + lowerRole + " in one step.");
}
}
}
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
从这里我们可以看到,这里并没有一上来就是用正则表达式,而是先将角色继承字符串转为一个 BufferedReader ,然后一行一行的读出来,再进行解析,最后再构建相应的 map。
五:Spring Security 中的角色继承问题的更多相关文章
- 看源码,重新审视Spring Security中的角色(roles)是怎么回事
在网上看见不少的博客.技术文章,发现大家对于Spring Security中的角色(roles)存在较大的误解,最大的误解就是没有搞清楚其中角色和权限的差别(好多人在学习Spring Security ...
- Spring Security 解析(五) —— Spring Security Oauth2 开发
Spring Security 解析(五) -- Spring Security Oauth2 开发 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...
- 六:Spring Security 中使用 JWT
Spring Security 中使用 JWT 1.无状态登录 1.1 什么是有状态? 1.2 什么是无状态 1.3 如何实现无状态 2.JWT 2.1 JWT数据格式 2.2 JWT交互流程 2.3 ...
- Spring Security中html页面设置hasRole无效的问题
Spring Security中html页面设置hasRole无效的问题 一.前言 学了几天的spring Security,偶然发现的hasRole和hasAnyAuthority的区别.当然,可能 ...
- Spring Security 中的过滤器
本文基于 spring-security-core-5.1.1 和 tomcat-embed-core-9.0.12. Spring Security 的本质是一个过滤器链(filter chain) ...
- [收藏]Spring Security中的ACL
ACL即访问控制列表(Access Controller List),它是用来做细粒度权限控制所用的一种权限模型.对ACL最简单的描述就是两个业务员,每个人只能查看操作自己签的合同,而不能看到对方的合 ...
- Spring Security 中的 Bcrypt
最近在写用户管理相关的微服务,其中比较重要的问题是如何保存用户的密码,加盐哈希是一种常见的做法.知乎上有个问题大家可以先读一下: 加盐密码保存的最通用方法是? 对于每个用户的密码,都应该使用独一无二的 ...
- 浅谈使用spring security中的BCryptPasswordEncoder方法对密码进行加密与密码匹配
浅谈使用springsecurity中的BCryptPasswordEncoder方法对密码进行加密(encode)与密码匹配(matches) spring security中的BCryptPass ...
- Spring Security中实现微信网页授权
微信公众号提供了微信支付.微信优惠券.微信H5红包.微信红包封面等等促销工具来帮助我们的应用拉新保活.但是这些福利要想正确地发放到用户的手里就必须拿到用户特定的(微信应用)微信标识openid甚至是用 ...
随机推荐
- String 类的常用方法都有那些?
1.indexOf():返回指定字符的索引. 2.charAt():返回指定索引处的字符. 3.replace():字符串替换. 4.trim():去除字符串两端空白. 5.split():分割字符串 ...
- Java学习日报8.5
package student;import java.util.*;public class student { Scanner sc=new Scanner(System.in); private ...
- 修改/查看ssh端口
修改ssh端口 vi /etc/ssh/sshd_config 将Port修改为需要的端口 Port 212 重启ssh服务 service sshd restart 查看ssh端口 netstat ...
- leetcode网站中找到的关于trie树的JAVA版本介绍
class TrieNode { // R links to node children private TrieNode[] links; private final int R = 26; pri ...
- 容器编排系统K8s之flannel网络模型
前文我们聊到了k8s上webui的安装和相关用户授权,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14222930.html:今天我们来聊一聊k8s上的网络 ...
- 多线程,线程类三种方式,线程调度,线程同步,死锁,线程间的通信,阻塞队列,wait和sleep区别?
重难点梳理 知识点梳理 学习目标 1.能够知道什么是进程什么是线程(进程和线程的概述,多进程和多线程的意义) 2.能够掌握线程常见API的使用 3.能够理解什么是线程安全问题 4.能够知道什么是锁 5 ...
- Eslint提示const关键字被保留
如果在使用eslint的时候提示: error Parsing error: The keyword 'const' is reserved 有可能是因为eslint默认审查的es5,需要明确让他审查 ...
- MATLAB OPC错误OPCenum service is not operating correctly解决办法
错误截图: 出错原因:C:\Windows\SysWOW64下没有OpcEnum.exe等文件,opc需要这些文件才能正常运行.有些系统内置了,有些系统没有. 解决方法:去opc官网https://o ...
- Kubernetes学习笔记之认识Kubernetes组件
前言:笔记知识点来源于Kubernetes官方文档说明,链接:https://kubernetes.io/docs/concepts/overview/components/ ,本记录仅仅是学习笔记记 ...
- .NET Core引入日志(Log4Net篇)
Demo版本信息如下: VS:2019 框架:.Net Core 3.1 Log4Net:2.0.12 思维导图: [1]添加依赖项 通过nuget添加Log4Net [2]创建公共类 添加公共类Lo ...