设为首页 收藏本站
查看: 710|回复: 0

[经验分享] 在前后端分离Web项目中,RBAC实现的研究

[复制链接]

尚未签到

发表于 2017-2-23 10:57:49 | 显示全部楼层 |阅读模式
  最近手头公司的网站项目终于渐渐走出混沌,走上正轨,任务也轻松了一些,终于有时间整理和总结一下之前做的东西。
  以往的项目一般使用模板引擎(如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环境变量:
权限KeyValue说明
管理员基础权限ShowManageBtn1显示“管理”按钮
pageSizeForManage50后台管理列表页行数
用户管理员权限ShowManageUsersBtn1后台管理显示“用户”按钮
用户管理员首页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 数量。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-346131-1-1.html 上篇帖子: 使用Grunt构建自动化开发环境 下篇帖子: Web开发学习之路是否有尽头
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表