使用spring security实现角色继承的权限控制

使用角色继承

spring security通过启用方法拦截,控制访问权限

注解 EnableGlobalMethodSecurity

注解@EnableGlobalMethodSecurity可以开启spring security的全局安全设置,其自动化配置位于类GlobalMethodSecurityConfiguration中。

该注解提供了三种类型的安全设置:

prePostEnabled

是否开启方法前后拦截,默认为false。

设置true

  • 可开启@PreAuthorize@PostAuthorize, 这两个注解可接受一个EL表达式,非常灵活的控制权限。从字面意思可直观看出,一个用于进入方法前,一个用于进入方法后,后者等同于放开权限,但是控制返回。

  • 可开启@PreFilter@PostFilter,从字面意思可以看出,用于方法前后的两个注解,该注解用于操作入参和出参。

securedEnabled

是否开启@Secure,默认false,该注解仅接受一个角色/权限,一般用于粗劣度控制。

jsr250Enabled

使用较少,从字面意思可以看出属于jsr250的范畴,目前位于jakarta项目。

启用jsr250,可以使用如 @DenyAll @AllowAll @RolesAllowed等注解。

使用@PreAuthorize开启基于角色继承的权限控制

树形结构的组织架构是一种比较常见的架构形式,基于组织架构的角色授予也通常会表显出一种树形结构,节点之上的角色通常会拥有子节点的权限,也表现出一种树形结构。

比如:

角色架构
经理
组长
成员
组织架构
组A
项目经理
组B
组员1
组员2
组员3

此时文字表示即:Role_经理 > Role_组长 > Role_成员

在接口方法上使用@PreAuthorize控制权限的写法即 @PreAuthorize("hasRole('Role_经理')") [依此类推]

为了实现角色继承,需要使用接口RoleHierarchy

RoleHierarchy接口

该接口只有一个方法,返回了角色的层级关系。

非常简单,不啰嗦,直接上代码。

@Bean
public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    Map<String, List<String>> map = MapBuilder.create(new HashMap<String, List<String>>())
            .put("ROLE_经理", Lists.newArrayList("ROLE_组长", "ROLE_成员"))
            .put("ROLE_组长", Lists.newArrayList("ROLE_成员"))
            .build();
    roleHierarchy.setHierarchy(RoleHierarchyUtils.roleHierarchyFromMap(map));
    return roleHierarchy;
}

只需要提供一个该接口的实现并注册即可

RoleHierarchyImpl是spring已经给我们的一种实现

解释

为什么这么简单即可实现角色的继承控制,其实就是一个AOP的问题。

找到@PreAuthorize是怎么实现功能的接口。
ReactiveMethodSecurityConfiguration中定义了一个方法拦截器

@Bean
public PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source, MethodSecurityExpressionHandler handler) {

	ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(
			handler);
	ExpressionBasedPreInvocationAdvice preAdvice = new ExpressionBasedPreInvocationAdvice();
	preAdvice.setExpressionHandler(handler);

	return new PrePostAdviceReactiveMethodInterceptor(source, preAdvice, postAdvice);
}

这里头的条条框框不细说,吧唧吧唧很多,最后就是拦截@PreAuthorize这个注解,然后解析这个注解里面的表达式。

跟代码最后会进入到MethodSecurityExpressionRoot这个里头,但是这个是依赖其父类SecurityExpressionRoot来实现的,这个父类提供的一系列final方法,都可以用到@PreAuthorize注解中(既然是EL表达式,当然支持逻辑运算与或非),找到hasRole方法开始跟代码(也许聪明如你,通过idea的插件,直接找到了这里,.)

private Set<String> getAuthoritySet() {
	if (roles == null) {
		Collection<? extends GrantedAuthority> userAuthorities = authentication
				.getAuthorities();

		if (roleHierarchy != null) {
			userAuthorities = roleHierarchy
					.getReachableGrantedAuthorities(userAuthorities);
		}

		roles = AuthorityUtils.authorityListToSet(userAuthorities);
	}

	return roles;
}

这里获取用户的角色时(字面意思看起来叫权限,角色=权限的集合),判断了如果注入了角色继承就会计算一把角色继承关系。

再顺着这里反过来找,最后会找到前面说的GlobalMethodSecurityConfiguration

在方法afterSingletonsInstantiated中有一段:

RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class);
if (roleHierarchy != null) {
	this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
}

此处获取了RoleHierarchy的一个单例实例,并注入进来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值