序言

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

首先,这里说明一下两种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. skyline中遍历fly工程树

    在skyline二次开发过程中,做空间分析总是要去读取工程中的shp图层.假设想获取工程树中“建筑物”图层,图层结构如下: 传统的方法是: var itemId=SGWorld.ProjectTree ...

  2. javascript中json对象与json字符串

    var data = "{'name':'张山','age':20}"; //转换字符串为json对象: var jsondata = JSON.parse(data); //转换 ...

  3. 使用ssh时报错:Service对象空指针异常

    有可能是spring容器不能自动生成service对象,导致空指针异常,常见的情况可能是在service前面加@Service注释

  4. jmeter-监听器介绍与使用

    12.jmeter-监听器介绍与使用 jmeter-监听器介绍与使用 察看结果树 Summary Report 聚合报告 Backend Listener Aggregate Graph 断言结果 C ...

  5. Leetcode144. Binary Tree Preorder Traversal二叉树的前序遍历

    给定一个二叉树,返回它的 前序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 递归: class S ...

  6. 解释性语言和非解释性语言,GIL锁

    解释性语言:python写的代码就被称为程序,cpu硬件能运行二进制代码指令.demo.py需要经过python解释器编译才做才能执行. 非解释性语言:例如c语言程序,同样需要写代码.demo.c这个 ...

  7. Redis源码解析:26集群(二)键的分配与迁移

    Redis集群通过分片的方式来保存数据库中的键值对:一个集群中,每个键都通过哈希函数映射到一个槽位,整个集群共分16384个槽位,集群中每个主节点负责其中的一部分槽位. 当数据库中的16384个槽位都 ...

  8. 【python之路35】网络编程之socket相关

    Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  9. [转]了解screen对象的常用视图属性

    前面的话 screen对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素高度和宽度等.每个浏览器中的screen对象都包含着各不相同的属性.本文将详细介绍screen对象的 ...

  10. 使用Jedis操作Redis-使用Java语言在客户端操作---String类型

    前提:需要引入Jedis的jar包. /** * 我的redis在Linux虚拟机Centos7中,192.168.222.129是我虚拟机的ip地址. */ private static Jedis ...