序言

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

首先,这里说明一下两种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. 不同目录cookie共享的问题解决 cookie不同页面访问不到的问题

    一般设置cookie的方法是setcookie(key, value, expire),参数分别的意思是建.值.过期时间,这里是大众的默认设置方法,但是忽略了一个问题,setcookie还有path与 ...

  3. HTMl中常用标签

    文本标记语言,即HTML(Hypertext Markup Language),是用于描述网页文档的一种标记语言. HTML之所以称为超文本标记语言,是因为文本中包含了所谓“超级链接”点.所谓超级链接 ...

  4. 《数据结构与算法分析——C语言描述》ADT实现(NO.03) : 二叉搜索树/二叉查找树(Binary Search Tree)

    二叉搜索树(Binary Search Tree),又名二叉查找树.二叉排序树,是一种简单的二叉树.它的特点是每一个结点的左(右)子树各结点的元素一定小于(大于)该结点的元素.将该树用于查找时,由于二 ...

  5. webServices学习二(小试牛刀。jdk 方式发布一个应用)

    一.前提 1.用Jdk1.6.0_21以后的版本发布一个WebService服务. 2.与Web服务相关的类,都位于javax.jws.*包中.  1.主要类有: 1.@WebService - 它是 ...

  6. javascript基础:语法与html结合方式

    一.基本语法: 1.与html结合方式 1.内部JS: *  定义<script>,标签体内容就是JS代码 2.外部JS: *  定义<script>,通过src属性引入外部的 ...

  7. LA3177 Beijing Guards

    Beijing Guards Beijing was once surrounded by four rings of city walls: the Forbidden City Wall, the ...

  8. Leetcode179. Largest Number最大数

    给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数. 示例 1: 输入: [10,2] 输出: 210 示例 2: 输入: [3,30,34,5,9] 输出: 9534330 说明: 输出结果 ...

  9. 常见问题:MongoDB基础知识

    常见问题:MongoDB基础知识 ·MongoDB支持哪些平台? ·MongoDB作为托管服务提供吗? ·集合(collection)与表(table)有何不同? ·如何创建数据库(database) ...

  10. AppServer初始化渠道

    1.写了一个拦截器(RequestInterceptor) 2.里边有个有一个doRequest()方法 3.初始化渠道的方法(initRequestContext()) -------------- ...