Spring Security权限管理原理

举报
torchstar 发表于 2022/11/30 22:44:57 2022/11/30
【摘要】 Spring Security权限管理原理

1.简介

授权是更具系统提前设置好的规则,给用户分配可以访问某一资源的权限,用户根据自己所具有的权限,去执行相应的操作,spring security提供的权限管理功能主要有两种:

基于过滤器的权限管理功能(FilterSecurityInterceptor)

基于AOP的权限管理功能(MethodSecurityInterceptor)

2. 核心概念

2.1 角色与权限

用户信息都保存在Authentication信息中,Authentication对象中有一个Collection<? extends GrantedAuthority> getAuthorities() 当需要进行鉴权时,就会调用该方法获取用户权限,进而做出判断。无论用户采取何种认证方式,都不影响授权。

从设计层面来讲,角色和权限是两个完全不同的东西,权限是一些具体操作,例如read、write,角色则是某些权限的集合,例如管理员、普通用户。

从代码层面讲,角色和权限并没有太大的不同。

至于Collection<? extends GrantedAuthority> getAuthorities() 的返回值,需要分情况对待:

(1) 如果权限系统设计的比较简单,用户<==>权限<==>资源三者之间的关系,那么getAuthorities就是返回用户的权限

(2) 如果权限系统设计的比较复杂,如用户<==>角色<==>权限<==>资源,此时将getAuthorities的返回值当作权限来理解。由于Spring Security并未提供相关的角色类,因此此时需要我们自定义角色类。

public class Role implements GrantedAuthority{

private String name;

private List<SimpleGrantedAuthority> allowedOperations=new ArrayList<>();

@Override

public String getAuthority{

 return name;

}

省略getter/setter方法

}

角色继承自GrantedAuthority,一个角色对应多个权限,然后在定义用户类的时候,将角色转为权限即可.

public class User implements UserDetails{

private List<Role> roles=new ArrayList<>();

@Override

public Collection<? extends GrantedAuthority> getAuthorities(){

List<SimpleGrantedAuthority> authorities=new ArrayList<>();

for(Role role:roles){

 authorities.addAll(role.getAllowedOperations());

}

return authorities.stream().distinct().collect(Collectors.toList());

}

省略getter/setter方法

}

2.2 角色继承

指角色存在一个上下级关系,例如ADMIN继承自USER,那么ADMIN就自动具备USER的所有权限。

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 > 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.

     */

    Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(

            Collection<? extends GrantedAuthority> authorities);

}

2.3 FilterSecurityInterceptor处理器

基于过滤器的权限过滤器(FilterSecurityInterceptor)有一个前置过滤器和后置过滤器,首先由前置处理器判断发起当前请求的用户是否具备相应的权限,如果具备则请求继续向下走,到达目标方法并执行完毕。在相应时,会经过FilterSecurityInterceptor,次吃由后置处理器再去完成收尾工作(后置过滤器一般不工作),如图2-3所示。


图2-3

2.4 前置过滤器

前置过滤器主要有两个核心组件,分别是投票器和决策器。

2.4.1 投票器

当投票器在投票时,需要两方面的权限:其一是当前用户具备哪些权限;其二是当前访问的URL需要哪些权限才能访问,投票器就是对这两种权限进行比较。其接口如下:

/**

 * Indicates a class is responsible for voting on authorization decisions.

 * <p>

 * The coordination of voting (ie polling {@code AccessDecisionVoter}s, tallying their

 * responses, and making the final authorization decision) is performed by an

 * {@link org.springframework.security.access.AccessDecisionManager}.

 *

 * @author Ben Alex

 */

public interface AccessDecisionVoter<S> {

    //同意

    int ACCESS_GRANTED = 1;

    //放弃

    int ACCESS_ABSTAIN = 0;

    //拒绝

    int ACCESS_DENIED = -1;

    //用来判断是否支持ConfigAttribute对象

    boolean supports(ConfigAttribute attribute);

    //用来判断是否支持受保护的安全对象

    boolean supports(Class<?> clazz);

    //具体投票方法,authentication可以提取出当前用户具备的权限;object表示受保护的安全对象,是一个FilterInvocation实例;attributes表示访问受保护对象所需的权限。返回值就是-1/0/1

  int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);

}

AccessDecisionVoter常用的实现类如下图2-4-1所示,本项目中主要用到RoleVoter和RoleHierarchyVoter。

RoleVoter:RoleVoter是根据登陆主体的角色进行投票,即判断当前用户是否具备受保护对象所需要的角色。需要注意的是,默认情况下,角色需要以ROLE_开始,否则supports方法会直接返回false。

RoleHierarchyVoter:继承自RoleVoter,投票逻辑和RoleVoter一样,不同的是RoleHierarchyVoter支持角色的继承,它通过RoleHierarchyImpl对象对用户所具有的角色进行解析,获得用户真正可触达的角色,而RoleVoter则直接调用 authentication.getAuthorities()方法获得用户的角色。


图2-4-1

2.4.2 决策器

决策器由AccessDecisionManager负责,AccessDecisionManager会同时管理多个投票器,由AccessDecisionManager调用投票器进行投票,然后根据投票结果做出相应的决策。

public interface AccessDecisionManager {

    void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)

            throws AccessDeniedException, InsufficientAuthenticationException;

    boolean supports(ConfigAttribute attribute);

    boolean supports(Class<?> clazz);

}

decide方法:是核心的决策方法,在这个方法中判断是否允许当前URL调用, 如果拒绝访问的话会抛出AccessDeniedException异常。

supports(ConfigAttribute) 方法:用来判断是否支持ConfigAttribute对象。

supports(Class)方法:用来判断是否支持当前安全对象。

和决策器相关的类关系,如图2-4-2所示,AccessDecisionManager会同时管理多个投票器,由AccessDecisionManager调用投票器进行投票,然后根据投票结果做出相应的决策,有一个抽象实现类AbstractAccessDecisionManager,AbstractAccessDecisionManager一共有三个子类:

AffirmativeBased:一票通过机制(默认即此)

ConsensusBased:少数服从多数机制,平局的话,则看 allowIfEqualGrantedDeniedDecisions 参数的取值

UnanimousBased:一票否决制


图2-4-2

2.5 权限元数据

2.5.1 ConfigAttribute

在介绍投票器的时候,在具体的投票方法vote中,受保护的对象所需要的权限保存在一个Collection集合中,集合中的对象是ConfigAttribute而不是GrantedAuthority,ConfigAttribute用来存储与安全系统相关的配置属性,也就是系统关于权限的配置,接口如下:

public interface ConfigAttribute extends Serializable{

 String getAttribute();

}

只有一个getAttribute方法返回具体的权限字符串,而GrantedAuthority则是通过getAuthority方法返回用户所具有的权限,随着两个类不同,但是二者的返回值都是字符串是可以比较的。其部分实现类如图2-5-1所示。


图2-5-1

2.5.2 SecurityMetadataSource

提供受保护的对象所需的权限,例如,用户访问了一个URL地址需要哪些权限才能访问?这个就由SecurityMetadataSource提供

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。