序言

由于最近一直卡在权限控制这个坎上,原来设计的比较简单的权限控制思路已经无法满足比较复杂一些的场景,因此一直在探索一种在大部分场景下比较通用的权限模型。

首先,这里说明一下两种RBAC权限模型分别是“基于角色的权限控制(Role-Based-Access-Control)”和“基于资源的权限控制(Resource-Based-Access-Control)”两种模型,这两种模型是Java最常见的权限控制的模型。它们之间的数据库结构区别并没有太大,甚至也可以一样。都是以最基础的五张表(用户表、角色表、用户-角色关系表、权限表、角色-权限关系表)组成,往后再复杂的业务再在这个基础上进行拓展,例如加入用户组、组织、模块等等概念,可以参考一下一这篇文章:

https://blog.csdn.net/qiaqia609/article/details/38102091

下面就以Spring Boot + Shiro为载体来具体记录一下。

1.准备数据库

首先还是最基础的五张表,后续的所有需求都是在这上面来拓展的,不管是基于角色还是基于资源都是差不多的数据结构。

这里还是贴一下Shiro的配置文件:ShiroConfig.java


  1. /**
  2. * @author phw
  3. * @date Created in 04-08-2018
  4. * @description 基于RESTFul风格的Shiro配置
  5. */
  6. @Slf4j
  7. @Configuration
  8. public class ShiroConfig {
  9. @Bean
  10. public DefaultWebSecurityManager securityManager(MyShiroRealm myShiroRealm) {
  11. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  12. securityManager.setRealm(myShiroRealm);
  13. /**
  14. * 关闭shiro自带的session管理
  15. * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
  16. */
  17. DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
  18. DefaultSessionStorageEvaluator evaluator = new DefaultSessionStorageEvaluator();
  19. evaluator.setSessionStorageEnabled(false);
  20. subjectDAO.setSessionStorageEvaluator(evaluator);
  21. securityManager.setSubjectDAO(subjectDAO);
  22. return securityManager;
  23. }
  24. @Bean
  25. public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
  26. ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
  27. //filterFactoryBean.setLoginUrl("/sign-in");
  28. //添加自己的过滤器并取名jwt
  29. Map<String, Filter> filterMap = new HashMap<>();
  30. filterMap.put("jwt", new JWTFilter());
  31. filterFactoryBean.setFilters(filterMap);
  32. filterFactoryBean.setSecurityManager(securityManager);
  33. filterFactoryBean.setUnauthorizedUrl("/401");
  34. //自定义url规则
  35. Map<String, String> filterRuleMap = new LinkedHashMap<>();
  36. // 访问401和404页面不通过我们的Filter
  37. /*filterRuleMap.put("/401", "anon");
  38. filterRuleMap.put("/403", "anon");
  39. filterRuleMap.put("/404", "anon");
  40. filterRuleMap.put("/sign-in", "anon");
  41. filterRuleMap.put("/sign-up", "anon");
  42. filterRuleMap.put("/sign-out", "logout");
  43. // 所有请求通过自己的JWT Filter
  44. filterRuleMap.put("/**", "jwt");*/
  45. /*List<Permission> permissions = permissionMapper.selectAll();
  46. for (Permission permission: permissions) {
  47. filterRuleMap.put(permission.getUrl(), permission.getInit());
  48. }
  49. filterFactoryBean.setFilterChainDefinitionMap(filterRuleMap);
  50. log.info("Shiro Filter Factory Bean inject successful...");*/
  51. return filterFactoryBean;
  52. }
  53. @Bean
  54. @DependsOn("lifecycleBeanPostProcessor")
  55. public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
  56. DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
  57. // 强制使用cglib,防止重复代理和可能引起代理出错的问题
  58. // https://zhuanlan.zhihu.com/p/29161098
  59. advisorAutoProxyCreator.setProxyTargetClass(true);
  60. return advisorAutoProxyCreator;
  61. }
  62. @Bean
  63. public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
  64. return new LifecycleBeanPostProcessor();
  65. }
  66. @Bean
  67. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
  68. AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
  69. advisor.setSecurityManager(securityManager);
  70. return advisor;
  71. }
  72. }

这里配置的是无状态(stateless)的shiro配置,因为要用到RESTful协议,所以需要使用jwt来保证api的安全。所以这里需要关闭掉Shiro自带的Session管理器,然后启用Shiro注解,自定义URL规则会在稍后说到。

2.Role Based Access Control

首先,来说一下比较常见的基于角色的权限控制。

我们所说的角色,其实就是一系列权限的集合,里面指定了哪种角色可以做什么事情,而用户也可以看作是一组角色的集合,所以我们在使用第一种rbac来进行权限控制的时候,一般是判断一个用户是否有某一个角色。我们用Shiro来讲就是像下面这样:


  1. @RequiresRoles("admin")
  2. //或者
  3. if(SecurityUtils.getSubject().hasRole("admin")) {
  4.     //do some thing...
  5.     System.out.println("I'm admin.")
  6. }

上面的代码是很多文章集成shiro后成功的样子,我当时也是这么做的,但是随着后来权限管理的业务越来越复杂,这种简单的或者说静态的权限管理模型已经不适用了,举个栗子:如果现在我要增加一个角色,名字叫teacher,让它也能打印一点东西。那么要做的就是首先在数据库添加角色名,然后修改权限代码,改成:

@RequiresRoles(value = {"admin", "teacher"}, logical = Logical.OR)

或者类似。也就是说,每一次变更需求,都需要变更代码,然后重新部署项目~~这显然是不怎么符合我们预期要求的。

因此这种模型只适合对权限需求变动不大的场景了。

当然,优点就是非常简单,开发起来使用起来非常方面,特别是配合上Shiro,一个注解就能搞定。

3.Resource Based Access Control

第二种基于资源的权限控制,是第一种的优化方案,我们还是来看看栗子:


  1. @RequiresPermissions("user:add")
  2. //或者
  3. if(SecurityUtils.getSubject().hasPermission("user:add")) {
  4. //do some thing...
  5. System.out.println("user:add");
  6. }

这种方式在一定程度上解决了上述第一种模型的问题,网上也有很多关于Resource Based Access Control的解释,但是这里我用我自己的话来解释一下,还是用上面的栗子,客户要求“admin”和“teacher”都有权限去打印一些东西。于是,第二种就不需要再修改代码了,我直接在前台给teacher授权“user:add”这个权限就可以了啊,因为这样已经很明确的指定了执行这个方法需要什么权限,就是“user:add”权限,我现在不管你是什么角色,什么组织,什么模块也好,只要你拥有这个“user:add”这个权限,那你就能执行这个方法。

但是,问题又来了。

如果现在需求变更,执行这个方法需要另外一个权限“user:edit”怎么办?是不是又得像上面那样,修改代码,重新部署项目。

所以,我们还需要一种能够完全动态控制权限的模型,不把任何权限或者角色写死,直接在数据库(前台)配置,每增加一个功能就注册一个功能然后指定它的需要的权限,就算需求变更,也不需要重新部署项目,只需要在前台稍微修改配置一下就能达到目的。

太晚了,今天就写到这里吧,预知后事如何,请听下回.......分解........

原文地址:https://blog.csdn.net/qq_33698579/article/details/80159823

两种RBAC权限控制模型详解的更多相关文章

  1. python RBAC权限控制模型扩展 基于JWT实现

    jwt,全称 json web token,是使用一定的加密规则生成的token串来保证登录状态.验证用户身份.做权限认证等工作 以往保存用户登录状态多用session实现,但是当服务涉及多台服务器分 ...

  2. php_ThinkPHP的RBAC(基于角色权限控制)详解

    一.什么是RBAC 基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注. 在RBAC中,权限与角色相关联,用户通 ...

  3. ThinkPHP框架下基于RBAC的权限控制模式详解

    这几天因为要做一个项目,需要可以对Web应用中通用功能进行封装,其中一个很重要的涉及到了对用户.角色和权限部分的灵活管理.所以基于TP框架自己封装了一个对操作权限和菜单权限进行灵活配置的可控制模式. ...

  4. IPVS和Nginx两种WRR负载均衡算法详解

    动机 五一临近,四月也接近尾声,五一节乃小长假的最后一天.今天是最后一天工作日,竟然感冒了,半夜里翻来覆去无法安睡,加上窗外大飞机屋里小飞机(也就是蚊子)的骚扰,实在是必须起来做点有意义的事了!    ...

  5. 两种CSS3圆环进度条详解

    晚上睡觉之前,我抽了1个多小时,研究了一下圆环进度条,结合从网上查阅的资料,我终于掌握了两种圆环的生成方法. 这次的效果就是单纯的CSS3效果,也没有写具体的JS,等以后有时间在好好整理一下吧~. 第 ...

  6. 两种Redis持久化原理的详解

    Redis为持久化提供了两种方式: RDB:在指定的时间间隔能对你的数据进行快照存储. AOF:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据. 本文将通过下面内容的介 ...

  7. 图文详解基于角色的权限控制模型RBAC

    我们开发一个系统,必然面临权限控制的问题,即不同的用户具有不同的访问.操作.数据权限.形成理论的权限控制模型有:自主访问控制(DAC: Discretionary Access Control).强制 ...

  8. Kubernetes-16:一文详解ServiceAccount及RBAC权限控制

    一.ServiceAccount 1.ServiceAccount 介绍 首先Kubernetes中账户区分为:User Accounts(用户账户) 和 Service Accounts(服务账户) ...

  9. yii2搭建完美后台并实现rbac权限控制实例教程

    1.安装yii2 未安装的请参考yii2史上最简单式安装教程,没有之一 或者参考yii2实战教程之详细安装步骤 已安装的请继续看下一步操作 2.配置数据库 2.1 配置数据库 修改common/con ...

随机推荐

  1. angular路由配置以及使用

    一.生成路由文件 按照惯例,有一个独立模块来配置相关路由,这个模块类的名字叫做AppRoutingModule,位于src/app下的app-routing.module.ts文件中. 使用CLI生成 ...

  2. leyou_01_自定义异常处理器

    1.自定义异常处理器,当程序发生异常时可以我们可以自己定义返回的,状态码和状态信息 2.当异常发生时调用我们的自定义异常 @RestController @RequestMapping("i ...

  3. Eureka配置问题

    在使用Spring Cloud做微服务开发中,经常会使用Eureka Server作为注册中心,如果配置不当可能会导致一些不可预期的异常信息.以下是我最近遇到的因为忽略了配置eureka.client ...

  4. 解决import javafx.geometry.Point2D无法导入的问题

    windows->preferences->java->compiler->errors/warning->deprecated and restricted API-& ...

  5. map 的使用 UVA156

    借用这一水题来熟悉map的操作,以前以为看过c++ primer,对map虽然不熟悉但用还是会用的,实际上手发现不是那么回事,还是有很多坑的 #include <iostream> #in ...

  6. PHP之文件的锁定、上传与下载的方法

    1.文件锁定 现在都在讲究什么分布式.并发等,实际上文件的操作也是并发的,在网络环境下,多个用户在同一时刻访问页面,对同一服务器上的同一文件进行着读取,如果,这个用户刚好读到一半,另一个用户就写入了消 ...

  7. SSH免密登录设置

    ******配置主机之间的免密ssh登陆 假如 A  要登陆  B 在A上操作: (1)首先生成密钥对 ssh-keygen   (提示时,直接回车即可) (2)再将A自己的公钥拷贝并追加到B的授权列 ...

  8. SSM1-Maven入门

    Maven项目管理工具 Svn eclipse   maven量级 1      Maven的简介 1.1    什么是maven 是apache下的一个开源项目,是纯java开发,并且只是用来管理j ...

  9. placeholder IE兼容,显示password

    从网上找了很多关于placeholder IE兼容性的问题,下边的这个js方法可以显示password. <!doctype html> <html lang="en&qu ...

  10. IoT: 物联网安全测试经验总结

    前言 今年早些时候,我参与了许多关于物联网解决方案的安全测试.主要目标是找出体系结构和解决方案中的漏洞.在这篇文章中,我将讨论一些与物联网解决方案的问题和挑战. 什么是物联网? 在你学习有关IPv6的 ...