微服务下权限校验方案

权限概述

任何一个系统都绕不开权限这两个字,一个良好的权限设计对一个系统起到了非常重要的作用,其实权限设计是个范围很大的问题,包括从数据库的表设计,权限控制方案,前端权限可见控制等等,权限按控制类别区分又分菜单权限,功能权限和资源权限,前端后分离后又面临着接口权限等等控制(针对接口权限有一些常用的框架,如shiro,spring security等),权限又会出现功能上的叠加问题,比如写权限(新增)是否一定拥有读权限(查看);如果采用RBAC,多角色的权限叠加问题,如果允许用户直接赋权又会遇到用户权限与角色权限的叠加等等,特别实在微服务流行的当前,一个系统可能由几十个上百个服务组成,如果权限放到每个服务上去控制将会是一场噩梦,网上权限方案林林总总,可以说没有最好的权限方案,只有合适的权限。

鉴权和权限控制

相信有一些兄弟对鉴权和权限控制理不清概念,鉴权只是去判断用户是否能访问平台的一个控制,一般先通过校验用户名和密码后,通过session,token,OAuth等去判断用户是否处于登录状态,这里并没有针对功能权限或资源权限的控制,权限控制一般都是在鉴权的基础上去做,简而言之,鉴权是判断用户的登录状态,权限控制是针对用户功能权限,资源权限等的一个过滤和控制

权限问题描述

在这里插入图片描述
目前我们系统的架构如上图所示,当前都是多节点,为了简化我只画了一个节点,我们权限系统包括要控制功能权限(菜单和按钮),资源权限,针对某类资源的一个权限控制,以及接口级别的权限控制。先说一下前提条件,我们是基于token的方式去做的鉴权,user-server提供用户的信息查询和权限查询功能,用户登录成功后,会将用户信息和权限信息(疑问一是否用户信息和权限信息要分开)缓存,然后gateway当请求过来是,判断请求head的token是否已经缓存,且能获取到用户信息,再往后释放请求。我这里数据库的数据采用RBAC,用户不直接配置权限。下面针对这个问题我列出我的疑问以及方法,希望能和大家一起讨论合适的方案

  • 权限功能叠加问题

毫无疑问,写权限必定伴随着读权限,要不然我新增一条数据后无法看到这条数据,系统看上去问题就很大了,也就是说我们的写权限必须得继承我们的读权限,比如我们现在有个功能叫查看资源列表,另一个功能叫添加资源,如果我们添加资源,无法看到资源列表是不是功能上就有走不通了?
但是我们在配置的时候我们勾选了添加功能未必一定会勾选查看列表的功能,那如何配置我们就可以新增资源拥有读的权限呢?
在这里插入图片描述
目前我想到两种方案:

  1. 将列表权限和菜单功能绑定,一旦拥有了资源管理这个菜单权限,则默认拥有了资源列表权限,这样将读权限上升一层,配置时无需考虑列表权限的问题
  2. 加权处理,上述功能虽然简单方便,但是将功能权限和菜单权限糅合在一起,对于没有列表功能或者后续需要删除列表功能,这样的需求扩展性就不高了,我们可以这么设计,假设资源列表权限的权限码是1,新增资源的权限码是2,我们存储用户新增权限时,存储的应该是1+2=3,这样我们就可以方便地处理权限的叠加功能(这里有个设计点,权限的码采用二进制1,2,4,8……,这样在做权限判断时可以使用未运行提升性能)
  • 统一功能(接口)权限问题
    在上述图中,我们可以清楚地知道,微服务模式下,如果每个服务自己去做权限校验,这会导致代码重复,扩展性低等等问题,那么,我们需要将权限统一处理(接口级别),这边想到的方式是将权限处理统一前置到网关层
    将权限控制到接口级别,则功能权限自然而然地就控制住了,那么怎么去控制接口级别地权限呢?
    在这里插入图片描述
    首先我们要讲功能与接口做一个绑定,我们可能在配置配置模块设计一个功能绑定接口的页面,这样可以动态去处理接口和功能间的映射,可能我们使用的是restful风格,所以如何去确定一个接口呢,我们需要这样几种属性
  1. 接口url,如:/api/res/1
  2. 接口请求方式,如:GET,POST,DELETE
  3. 如果服务比较多,为了避免重复也可以添加一个appcode去限定接口的范围

如此我们可以在用户登录的时候读取用户的权限信息(有权限的接口信息),存放到redis缓存里面,然后用户再次请求时,gateway去缓存里面拿到接口信息和当前请求的接口信息做对比,继而判断当前用户是否有该接口的权限
这里有个问题是如上图所示,当用户请求接口1时,他只有功能1的权限,功能2的权限是没有的,哪怕他第一个接口请求通过,后面的接口都会报403,前端就可以给出没有权限的判定

  • 数据权限问题
    数据权限我觉得应该是这个权限里面最难的,如果需要做数据权限必然是要满足以下几个场景

1.该资源数据贯穿整个系统,整个系统是依附于该数据而创建的
2.该数据挂载在某个组织树下,如部门组织结构

如果不满足以上两点,资源权限的控制就非常复杂了,一是资源完全平铺,如数十万的数据在其中进行勾选配置功能毫无体验感,在做资源权限的校验sql中使用in大量数据效率也低下
另外在微服务下,数据权限的校验则需要下放到各个微服务模块,因为数据权限的校验不具备全局通用性,我们在各个微服务模块可以使用aop的方式去判断当前用户当前接口是否拥有该资源的权限

  • 权限变更问题
    这个也是一个难点,比如用户的权限发生变更了,怎样让用户立马感知并更新权限呢?
    因为目前我们的权限信息是存放到缓存的,所以权限发生变更时需要更新缓存信息,目前有两种方式处理

1.用户信息和权限信息缓存在同一个对象里面,此时如果权限发生变更,我们可以做用户的强制登出处理,这样用户再次登录就可以拿到新的权限信息(里面有些细节,比如角色的功能添加和删除,我们就需要找到该角色下绑定的在线用户,然后做统一登出处理,如此我们就需要维护在线用户的信息),此方式实现逻辑简单,唯一的麻烦是需要用户重新登录,体验较差
2.用户信息和用户权限信息分开缓存,我们则会在权限信息发生变更时,删除用户的权限缓存,当用户再次请求时,发现没有权限信息,则重新去数据库获取,然后放到缓存,再做对比,此方式的好处是用户不用再次登录,我唯一担心的是用户信息和权限信息不一致的问题

至此,权限方面的问题我都讲解了我的一些想法,当然也没法面面俱到,市面上的权限相关文章大多是理论层面的概述,于是记下此文,希望有相关需求的小伙伴能和我一起交流,共同成长

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值