【Spring Security】安全框架学习(十二)

6 其他小问题

6.0 其他权限校验方法

我们前面都是使用@PreAuthorize注解,然后在在其中使用的是hasAuthority方法进行校验。Spring Security还为我们提供了其它方法.

例如:hasAnyAuthority,hasRole,hasAnyRole,等。

这里我们先不急着去介绍这些方法,我们先去理解hasAuthority的原理,然后再去学习其他方法就会更容易理解。并且我们也可以选择定义校验方法,实现我们自己的校验逻辑。

hasAuthority方法实际是执行到了SecurityExpressionRoot的hasAuthority,大家只要断点调试既可知道它内部的校验原理。

它内部其实是调用authentication的getAuthorities方法获取用户的权限列表。然后判断我们存入的方法参数数据在权限列表中。

6.0.1 源码理解

在 SecurityExpressionRoot 这个类的内部可以看到hasAuthority方法是怎么实现的。

【Spring Security】安全框架学习(十二)_第1张图片

这个方法的参数authority实际上就是 @PreAuthorize(“hasAuthority(‘test’)”) 这个注解中的 ‘test’ 。可以注意的是,在hasAuthority方法的内部又调用了一个方法 hasAnyAuthority 。

这个方法接收了一个字符串的可变参,也就是说它本身可以接收多个字符串的参数,可见它的本质还是一个数组。

【Spring Security】安全框架学习(十二)_第2张图片

同时在 hasAnyAuthority 方法内部 又调用了 hasAnyAuthorityName方法。但是我们并不用关心它在内部的调用链路,只需要关注核心的实现代码就可以了。

【Spring Security】安全框架学习(十二)_第3张图片

在 hasAnyAuthorityName 这个方法里面有两个参数,一个参数是prefix,在hasAnyAuthority方法中传进来的时候是null。第二个参数roles也就是之前的authorities传教来的参数。

在第二行使用了一个set集合、泛型是String的变量,在创建的时候调用了方法getAuthoritySet (获取权限集合)。

【Spring Security】安全框架学习(十二)_第4张图片

观察 getAuthoritySet 方法 ,发现它的执行流程是首先判断roles是否为空,如果为空就走到if的里面去,而接下来的一条语句就是核心代码。这里接收了 this.authentication ,这个就是我们之前在filter中存入到holder当中的对象,即UsernamePasswordAuthenticationToken,可以知道这里userAuthorities拿到了我们的权限对象,最终就调用到了我们自己在LoginUser类中重写的方法里去。

然后又将我们的数据进行了处理,把list集合转化为了set集合。

最终返回的set集合,是一个String类型的。

这个set集合被hasAnyAuthorityName 方法拿到,而这个权限信息其实就是当前用户所具有的权限信息。然后判断当前用户有没有访问接口的权限,hasAnyAuthorityName 方法的roles参数就是访问接口所需要具有的权限。就是拿roles这个元素到getAuthoritySet 判断是否存在。

接着在hasAnyAuthorityName 方法中使用for循环遍历参数。在for循环中拿着role去执行了方法 getRoleWithDefaultPrefix ,这个方法在内部对字符串做了一个拼接。它会拿一个前缀和我们的权限字符串做一个拼接。
【Spring Security】安全框架学习(十二)_第5张图片

但是回到hasAnyAuthorityName 方法中,传进去的prefix前缀的值实际上是null,也就是说实际上并没有做一个拼接,没有前缀,最终的结果也就是原本的字符串。如果有权限就会返回一个true,没有权限就会返回一个false。

从上面的源码中我们可以发现,hasAnyAuthority方法实际上可以传入多个权限,只只要用户有其中任意一个权限都可以访问对应资源。

传入多个权限的写法:

//标注在controller层
@PreAuthorize("hasAuthority('test','admin')")

hasRole要求有对应的角色才可以访问,但是它内部会把我们传入的参数拼接上ROLE_后再去比较。所以这种情况下要用用户对应的权限也要有ROLE_这个前缀才可以。

如果直接向下面这种写法然后直接执行的话,会访问不了。

@PreAuthorize("hasRole('test')")

我们用户即使有这个权限,也会访问不了,我们来看一下这个对应的源码。
【Spring Security】安全框架学习(十二)_第6张图片

在hasRole这个方法内部又调用了一个方法hasAnyRole,

【Spring Security】安全框架学习(十二)_第7张图片

这个方法在传入参数的时候,this.defaultRolePrefix 传进来一个 ‘ROLE_’ 。是role的一个前缀,而这个 “ROLE_” 就是默认的前缀。

在这里插入图片描述

在hasAnyAuthorityName方法内部,它获取到了这个权限,还要拿这个权限拼接上一个前缀,拼接之后再和集合中的元素做一个判断。

hasAnyRole有任意的角色就可以访问。它内部也会把我们传入的参数拼接上 ROLE_ 后再去比较。所以这种情况下要用用户对应的权限也要有**ROLE_**这个前缀才可以。

@PreAuthorize("hasRole('admin','test')")

你可能感兴趣的:(后端框架学习,安全,java,Spring,Security,spring,boot,spring)