为了后续对 AccessDecisionManager 的介绍,我们先来提前对 AccessDecisionVoter 做个简单的了解,然后,在捎带手自定义一个 AccessDecisionVoter

AccessDecisionVoter 的注释介绍如下:

Indicates a class is responsible for voting on authorization decisions. 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}.

什么意思呢?

翻译过来就是,AccessDecisionVoter 是一个投票器,负责对授权决策进行表决。然后,最终由唱票者AccessDecisionManager 统计所有的投票器表决后,来做最终的授权决策。

先来看几种常用的投票器。

WebExpressionVoter

最常用的,也是 Spring Security 框架默认 FilterSecurityInterceptor 实例中 AccessDecisionManager 默认的投票器 WebExpressionVoter。其实,就是对使用 http.authorizeRequests() 基于 Spring-EL进行控制权限的的授权决策类。

http.authorizeRequests().anyRequest().authenticated().antMatchers().permitAll().antMatchers().hasRole().antMatchers().hasAuthority()......

他还需要一个 ExpressionHandler,感兴趣的话,可以去看一下文章史上最简单的Spring Security教程(十七):FilterSecurityInterceptor默认初始化逻辑剖析里面有对 WebExpressionVoter  ExpressionHandler 的相关介绍。

AuthenticatedVoter

针对 ConfigAttribute#getAttribute() 中配置为 IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY 权限标识时的授权决策。因此,其投票策略比较简单:

public int vote(Authentication authentication, Object object,Collection<ConfigAttribute> attributes) {int result = ACCESS_ABSTAIN;
​for (ConfigAttribute attribute : attributes) {if (this.supports(attribute)) {result = ACCESS_DENIED;
​if (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())) {if (isFullyAuthenticated(authentication)) {return ACCESS_GRANTED;}}
​if (IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())) {if (authenticationTrustResolver.isRememberMe(authentication)|| isFullyAuthenticated(authentication)) {return ACCESS_GRANTED;}}
​if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) {if (authenticationTrustResolver.isAnonymous(authentication)|| isFullyAuthenticated(authentication)|| authenticationTrustResolver.isRememberMe(authentication)) {return ACCESS_GRANTED;}}}}
​return result;}
}

PreInvocationAuthorizationAdviceVoter

用于处理基于注解 @PreFilter 和 @PreAuthorize 生成的 PreInvocationAuthorizationAdvice,来处理授权决策的实现。还记得我们最早使用 @PreAuthorize 来进行权限控制的介绍吗?史上最简单的Spring Security教程(十二):@PreAuthorize注解实现权限控制。

public int vote(Authentication authentication, MethodInvocation method,Collection<ConfigAttribute> attributes) {
​// Find prefilter and preauth (or combined) attributes// if both null, abstain// else call advice with them
​PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
​if (preAttr == null) {// No expression based metadata, so abstainreturn ACCESS_ABSTAIN;}
​boolean allowed = preAdvice.before(authentication, method, preAttr);
​return allowed ? ACCESS_GRANTED : ACCESS_DENIED;
}

RoleVoter

角色投票器。用于 ConfigAttribute#getAttribute() 中配置为角色的授权决策。其默认前缀为 ROLE_,可以自定义,也可以设置为空,直接使用角色标识进行判断。这就意味着,任何属性都可以使用该投票器投票,也就偏离了该投票器的本意,是不可取的。

public int vote(Authentication authentication, Object object,Collection<ConfigAttribute> attributes) {if (authentication == null) {return ACCESS_DENIED;}int result = ACCESS_ABSTAIN;Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
​for (ConfigAttribute attribute : attributes) {if (this.supports(attribute)) {result = ACCESS_DENIED;
​// Attempt to find a matching granted authorityfor (GrantedAuthority authority : authorities) {if (attribute.getAttribute().equals(authority.getAuthority())) {return ACCESS_GRANTED;}}}}
​return result;
}

注意,决策策略比较简单,用户只需拥有任一当前请求需要的角色即可,不必全部拥有

RoleHierarchyVoter

基于 RoleVoter,唯一的不同就是该投票器中的角色是附带上下级关系的。也就是说,角色A包含角色B,角色B包含 角色C,此时,如果用户拥有角色A,那么理论上可以同时拥有角色B、角色C的全部资源访问权限。

/*** 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 &gt; ROLE_B and ROLE_B &gt; 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.*/
public Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(Collection<? extends GrantedAuthority> authorities);

注意,同 RoleVoter 的决策策略,用户只需拥有任一当前请求需要的角色即可,不必全部拥有

以上就是常用的投票器,接下来,我们自定义一个投票器,与 RoleVoter 策略正好相反,必须拥有当前请求所需的全部角色才能访问。尝试一下。

@Override
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {if (authentication == null) {return ACCESS_DENIED;}
​int result = ACCESS_ABSTAIN;Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
​for (ConfigAttribute attribute : attributes) {if (this.supports(attribute)) {result = ACCESS_DENIED;
​// Attempt to find all matching granted authorityfor (GrantedAuthority authority : authorities) {if (attribute.getAttribute().equals(authority.getAuthority())) {result = ACCESS_GRANTED;break;}}
​if (result == ACCESS_DENIED) {return ACCESS_DENIED;}}}
​return result;
}

其它逻辑包括 rolePrefix、supports等,与 RoleVoter完全一致,只修改决策部分的逻辑:只要当前请求所需任一角色不在用户拥有的角色范围内,即代表没有授权,拒绝访问。

其它详细源码,请参考文末源码链接,可自行下载后阅读。

源码

github

https://github.com/liuminglei/SpringSecurityLearning/tree/master/19

gitee

https://gitee.com/xbd521/SpringSecurityLearning/tree/master/19

回复以下关键字,获取更多资源

SpringCloud进阶之路 | Java 基础 | 微服务 | JAVA WEB | JAVA 进阶 | JAVA 面试 | MK 精讲

笔者开通了个人微信公众号【银河架构师】,分享工作、生活过程中的心得体会,填坑指南,技术感悟等内容,会比博客提前更新,欢迎订阅。

技术资料领取方法:关注公众号,回复微服务,领取微服务相关电子书;回复MK精讲,领取MK精讲系列电子书;回复JAVA 进阶,领取JAVA进阶知识相关电子书;回复JAVA面试,领取JAVA面试相关电子书,回复JAVA WEB领取JAVA WEB相关电子书。

史上最简单的Spring Security教程(十九):AccessDecisionVoter简介及自定义访问权限投票器相关推荐

  1. microsoftsql新建登录用户登录失败_史上最简单的Spring Security教程(九):自定义用户登录失败页面...

    生活中肯定存在这样的场景,在登录某个网站时,难免会忘记密码,或是验证码输入错误,造成多次尝试.所以,有必要适度的提醒用户,到底是什么原因造成了登录失败,如用户名密码不正确.验证码错误等等.由于 Spr ...

  2. 史上最简单的 Spring MVC 教程(九)

    1 前言 在史上最简单的 Spring MVC 教程(五.六.七.八)等四篇博文中,咱们已经分别实现了"人员列表"的显示.添加.修改和删除等常见的增.删.改.查功能.接下来,也就是 ...

  3. 史上最简单的Spring Security教程(二十八):CA登录与默认用户名密码登录共存详细实现及配置

    ​在前面的文章中,我们自定义了一些CA登录相关的类,如 CertificateAuthorityAuthenticationToken.CertificateAuthorityAuthenticati ...

  4. 史上最简单的Spring Security教程(八):用户登出成功LogoutSuccessHandler高级用法

    ​大多数业务场景下,自定义登出成功页面也满足不了一些要求,更别提默认的登出成功页面.这时候,就需要别的方案支持,幸运的是,Spring Security 框架还真就非常贴心的提供了这样一个接口 Log ...

  5. 史上最简单的spark系列教程 | 完结

    <史上最简单的spark系列教程>系列: 与其说是教程不如说是改良后的个人学习笔记|| 教程参考自:<spark官方文档>,<spark快速分析>,<图解Sp ...

  6. 2010年史上最简单的做母盘教程

    2010年史上最简单的做母盘教程 辛苦了两个小时才把教程写完....写得不好大家多多包涵 其实做母盘是一件十分简单的事,只要大家敢去试就能成功的,这教程只给小白看的,老鸟路过指点一下. 本人是珠海信佑 ...

  7. 如何在 CSDN 中增加博客访问量 史上最简单的博客教程 学会之后博客访问量直线上升。

    蹭热度 如何蹭是问题.下面分几点 你发布的有关技术是什么 你发布的是否是别人发布过的东西 你发布的东西在别人是怎样搜索的. 其实重点在流量,也就是点击.点击到位了,无论你文章来自哪里,或者说抄自哪里, ...

  8. 呕心沥血整理出的史上最简单的IntelliJ IDEA教程,快来看哟!

    前言 IntelliJ IDEA(简称IDEA),是Java语言开发的集成环境,IDEA在业界被公认为是最好的Java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.各类版本工具( ...

  9. 用spring security设置用户jwt令牌和设置接口访问权限案例

    文章目录 1.配置Swagger 2.spring security配置 3.用户校验逻辑 注册和登录接口 dao层 service层 pojo层 4.加密验证逻辑 5.生成令牌逻辑 身份验证提供者: ...

最新文章

  1. 通过响应式web设计,使本站支持手机浏览
  2. 珠海市建设工程质量监督检测站
  3. 知识点讲解五:处理js异步加载问题
  4. 推你所想,神策智能推荐 Demo 上线(可免费体验)
  5. GoldenGate 12.3微服务架构与传统架构的区别
  6. 联想ThinkCentre M8400t-n000等高配电脑重装成xp蓝屏0xc000007b代码
  7. java treeset比较,java中TreeSet的两种排序比较的方式
  8. 验证guid()类型值的函数
  9. java编写一个个人通信录程序
  10. 企业如何高效用云?| 资深运维架构师细说云架构下的运维体系构建
  11. 【03】AngularJS 简介
  12. 东北大学金工实习理论考试重点
  13. awk将txt转换为csv
  14. Microsoft Office 2016(ProPlus/Visio/Project) VOL 简体中文版
  15. 金蝶k3服务端显示服务器不是有效的,金蝶k3远程服务器设置
  16. 西南科技大学OJ系统 #941: 有序顺序表的合并操作的实现
  17. mysql 中电话号码_类型-电话号码和地址的mysql数据类型
  18. PDFObject的使用(转)
  19. 德州农工计算机科学教授,德州农工大学计算机博士招生中,机器学习与数据挖掘方向,有奖学金...
  20. android 方向传感器应用

热门文章

  1. 小学计算机课程表说课稿,小学信息技术《创建课程表》说课稿
  2. 【SWAT水文模型】SWAT水文模型建立及应用第二期:土地利用数据的准备
  3. android--MAT、DDMS 等内存查看工具
  4. 【踩坑系列】 SpringBoot ,SpringSecurity,activiti 项目无法正常跳转到登录界面
  5. 北斗导航 | 初尝PPP-RTK禁果
  6. python rest api 书籍_python rest api 中文
  7. 四川信息职业技术学院计算机网络专业,四川航天职业技术学院计算机科学系专业介绍...
  8. 微信零钱交易记录怎么彻底删除,这些方法等你来盘
  9. 阿里云MQTT + STM32 + MQTT + ESP8266 01S WIFI 实现远程继电器控制开关和采集温湿度 登录阿里云网站,进入物联网云平台
  10. MacBook如何快速添加指纹!