在前后端分离Web项目中,RBAC实现的研究

 

最近手头公司的网站项目终于渐渐走出混沌,走上正轨,任务也轻松了一些,终于有时间整理和总结一下之前做的东西。

以往的项目一般使用模板引擎(如ejs)渲染出完整页面,再发送到浏览器展现。但这次项目的处理方式不同,整个项目由前端AngularJS和后端NodeJS进行了前后端的分离。后端Nodejs提供静态文件服务和API接口,前端则通过AJAX请求调用后端的API,已JSON数据包来进行数据交换。

同时,用户权限管理方面,我选用了RBAC(基于角色的访问控制,Role-based access control)最基本的实现来管理(用户表、角色表、权限表、用户-角色关联表、角色-权限关联表)。而当我实际开发这个模块的时候,立刻就意识到和以往项目的区别:

在使用后端模板引擎渲染页面的时候,后端可以根据用户权限有选择地渲染一些受限的页面元素。

而在前后端分离的开发方式下,由于后端并不渲染任何页面,是否显示某个页面元素,完全是由前端来决定的。

对此,我考虑了一种相对简单的方式:

将用户最终所具有的所有权限通过API返回给前端,前端根据权限控制页面元素。

后端本身就知道用户权限,每个API接口的入口处添加权限的检查。

然而,这样的处理方式是有一定局限性的:

后端每个API入口处都必须写一遍检查。

仅仅到权限级别,太过宽泛,无法进行粒度更小的控制。

权限虽然可以通过用户、角色来实现可配置,但是权限与页面元素、API是否允许调用之间却是由代码编写确定,这部分是无法配置的。

这显然不是我能做到的最佳解决方案。

至少对于后端,我想要的是一种更加灵活可配置,并对业务代码透明的权限检查方式

于是,我在之前解决方案的基础上,做了进一步细化,并将页面元素、API都当作资源来看待。同时,为了前端可以做更加灵活的控制,页面元素进一步抽象成一份Key-Value数据(我称之为页面环境变量ENV),供前端使用。这样,用户经过RBAC模块最终得到的不是权限,而是“允许访问的API列表(支持*和**通配)”和“环境变量”。

于是,我在权限表之后,又增加了:API路径表、ENV环境变量表、及相关关联表。例如:

角色-权限:

角色 权限
用户 基础权限
管理员 管理员基础权限
用户管理员 用户管理员权限
用户管理员首页

权限-API路径:

权限 API路径 说明
基础权限 /public/** 所有公共资源
/myAccount/** 个人账户所有操作
用户管理员权限 /manage/users/do/list 后台管理用户列表
/manage/users/*/do/get 后台管理查看任意用户信息

权限-ENV环境变量:

权限 Key Value 说明
管理员基础权限 ShowManageBtn 1 显示“管理”按钮
pageSizeForManage 50 后台管理列表页行数
用户管理员权限 ShowManageUsersBtn 1 后台管理显示“用户”按钮
用户管理员首页 manageHomePageUrl /main.html#/manage/users 后台管理页面首页地址

其中,用户最终的API路径表用于后端API进行权限的检查。ENV环境变量返回给前端供其控制页面。

具体而言:

后端只要在请求入口(而不是单个API入口)处,对请求的URL路径和上面的“允许访问的API路径列表”进行比对。请求的路径如在列表中,则通过检查,之后的业务逻辑无需再关心权限问题。如不在列表中,则直接返回拒绝请求。

前端则可以直接使用ENV环境变量中的Key-Value来控制页面,

如配合AngularJS的ng-show: <div ng-show="hasEnv('ShowManageBtn')">...</div>

通过使用这种方式,不仅避免了对每个权限进行 if...else 处理,同时,对后续修改及配置提供了相当大的便利。

当然,这种处理方式也有一些注意点(或者说缺点)。

1. API路径设置要合理有规律,方便通配(单个星号通配1层路径、两个星号通配多层路径)

统一路径命名:如管理类接口都由/manage开头,那么在配置时,只需要使用/manage/**即可通配所有的路径(包括:/manage/home、/manage/users/list)。

做好分层规划:如管理类接口可以按功能细分 /manage/users/**、/manage/posts/**

以统一的动词结尾:如只读权限可以配置为/manage/**/do/get,添加权限可以配置为/manage/**/do/add。

处理对象的ID写进路径:如查看用户信息的路径为 /manage/users/1/do/get、/manage/users/2/do/get,可以配置权限为/manage/users/*/do/get

2. 避免粒度过细

过细的粒度会导致API路径以及ENV环境变量数量的暴增。不仅管理起来麻烦,而且也会一定程度上影响权限检查时的效率。

对于API路径的粒度,一定要严格管理API路径格式以及尽量使用通配,详细见上述第1条。

对于ENV环境变量,可以考虑合并一些总是一起出现的内容。如系统只区分读权限和写权限,则添加、编辑、删除按钮的控制就可以合并为一个 {"btnForWrite": 1} 来处理,而不是为每个按钮都添加一个ENV环境变量。甚至可以将Value设置为一个JSON来保存多个值 {"canWrite":{"addBtn":1, "editBtn":1}}

3. 设置不进行RBAC认证的API路径白名单

比如之前例子中的“基础权限”中的 /public/** 这类肯定允许访问的路径,其实是没有必要特地添加一个权限来管理的。

这类API路径应当写到网站配置中,作为不进行RBAC认证的API路径。

4. 对API路径及ENV环境变量列表进行缓存

每个请求都查询数据库来获取API路径列表显然有点浪费资源。可以针对每个用户,将API列表及环境变量保存到Session中,这样只有第一次请求时才会查询数据库,之后的请求在RBAC检查权限时,只需要从Session取回之前缓存的API列表和ENV环境变量即可。但要注意用户权限在改变时,需要及时令Session中的数据失效。

我在项目中的做法是保存进Redis中,并以 cache@rbac#userId:{userId} 为Key进行保存。当用户角色发生变化时,按照 cache@rbac#userId:{userId} 清除当前用户的权限缓存即可;当角色、权限、API路径、ENV环境变量发生变化时,由于不是很好明确到底影响多少用户,所以直接按照 cache@rbac#userId:* 来清除所有用户的权限缓存。

总结:前后端分离的项目中,

1. 后端服务器仅仅暴露API,所以功能级权限管理可以处理为API的访问控制。

2. 前端页面需要从后端服务器获知如何控制页面元素。同时,直接返回控制方式或具体数值可以减少前端 if...else 数量。

/*
* Yiling Zhou
* Shanghai, China
* -.-- .. .-.. .. -. --. / --.. .... --- ..-
* ... .... .- -. --. .... .- .. --..-- / -.-. .... .. -. .-
*/
 
 
标签: 权限RBACAngularJSNodeJS

前后端分离Web项目中,RBAC实现的研究的更多相关文章

  1. 在前后端分离Web项目中,RBAC实现的研究

    最近手头公司的网站项目终于渐渐走出混沌,走上正轨,任务也轻松了一些,终于有时间整理和总结一下之前做的东西. 以往的项目一般使用模板引擎(如ejs)渲染出完整页面,再发送到浏览器展现.但这次项目的处理方 ...

  2. angular+ionic前后端分离开发项目中的使用

    Ionic基于AngularJS构建而成,所以学习一些AngularJS的知识很有必要.Ionic并没有独立开发一套完整的Web应用框架,而是对AngularJS进行了扩展,给它添加了大量界面组件和其 ...

  3. 如何在node和vue前后端分离的项目中使用极客验证,用node的方式

    1.用express的脚手架和vue-cli的脚手架搭建的项目目录如下图 2.在vue-client的src/component新建一个login.vue文件,作为登录页面,代码如下 <temp ...

  4. 【转】前后端分离的项目如何部署发布到Linux

    前后端分离的项目如何部署发布到Linux 前期准备 1.服务器的基本配置信息2.本机远程连接服务器的工具(xshell.xftp或者mobaXterm等等,看你自己喜欢) 第一步:部署环境 1.安装j ...

  5. java结合node.js非对称加密,实现密文登录传参——让前后端分离的项目更安全

    前言   在参考互联网大厂的登录.订单.提现这类对安全性操作要求较高的场景操作时发现,传输的都是密文.而为了目前项目安全,我自己负责的项目也需要这方面的技术.由于,我当前的项目是使用了前后端分离技术, ...

  6. gin+vue的前后端分离开源项目

    该项目是gin+vue的前后端分离项目,使用gorm访问MySQL,其中vue前端是使用vue-element-admin框架简单实现的: go后台使用jwt,对API接口进行权限控制.此外,Web页 ...

  7. spring boot 2.0.0 + shiro + redis实现前后端分离的项目

    简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大 ...

  8. docker-compose + nginx部署前后端分离的项目

    安装docker 安装必要的系统工具 # 更新yum工具 yum update -y # 安装必要的工具 yum install -y yum-utils device-mapper-persiste ...

  9. SpringBoot+MyBatisPlus+ElementUI一步一步搭建前后端分离的项目(附代码下载)

    场景 一步一步教你在IEDA中快速搭建SpringBoot项目: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/87688277 ...

随机推荐

  1. Joomla3.1.1在64位win7下安装

    将下载的joomla压缩包解压到Apache下的htdocs文件夹中. 打开Apache服务器,在浏览器输入http://localhost:8081/Joomla/ 即可进入Joolma的安装配置界 ...

  2. Spring Configuration Check Unmapped Spring configuration files found

    Spring Configuration Check Unmapped Spring configuration files found 项目中有xml文件,但没有被用IntelliJ 导入现有工程时 ...

  3. Spring Boot 分布式Session状态保存Redis

    在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而打到另外一台服务器的时候,session丢失. 常规的解决方 ...

  4. 操作系统概念学习笔记 10 CPU调度

    操作系统概念学习笔记 10 CPU调度 多道程序操作系统的基础.通过在进程之间切换CPU.操作系统能够提高计算机的吞吐率. 对于单处理器系统.每次仅仅同意一个进程执行:不论什么其它进程必须等待,直到C ...

  5. 单链表的插入删除操作(c++实现)

    下列代码实现的是单链表的按序插入.链表元素的删除.链表的输出 // mylink.h 代码 #ifndef MYLINK_H #define MYLINK_H #include<iostream ...

  6. 内省(一)之Introspector、BeanInfo、PropertyDescriptor

    内省(Introspector)是专门用来操作JavaBean属性的.不是所有的字段(Field)都能被称之为属性,只有某些字段具有getXXX或setXXX方法的才能称之为属性,当然要称为是一个Be ...

  7. zipkin分布式链路追踪系统

    基于zipkin分布式链路追踪系统预研第一篇   分布式服务追踪系统起源于Google的论文“Dapper, a Large-Scale Distributed Systems Tracing Inf ...

  8. WM_PAINT与WM_ERASEBKGND(用户操作和API这两种情况产生消息的顺序有所不同)

    1)当WM_PAINT不是由InvalidateRect产生时,即由最大化,最小化等产生时,或者移动产生(移动有时只会产生WM_ERASEBKGND消息)系统先发送WM_ERASEBKGND消息,再发 ...

  9. Minor GC、Major GC和Full GC之间的区别(转)

    在 Plumbr 从事 GC 暂停检测相关功能的工作时,我被迫用自己的方式,通过大量文章.书籍和演讲来介绍我所做的工作.在整个过程中,经常对 Minor.Major.和 Full GC 事件的使用感到 ...

  10. 《Windows核心编程》第一讲 对程序错误的处理

    一个Windows函数通常都有一个有意义的返回值类型,它标志着这个函数的运行状态,即函数运行成功与否.windows常用的函数类型如下图: 从系统内部来讲,当一个Windows函数检测到一个错误时,它 ...