前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >有赞移动权限体系建设

有赞移动权限体系建设

作者头像
用户6021891
发布2021-03-22 10:53:36
9080
发布2021-03-22 10:53:36
举报

一、背景

权限管理是一个几乎所有大中型 B 端系统都会涉及的重要组成部分,其目的是对整个系统进行权限控制,避免造成误操作及数据泄露等风险问题。在充分调研了商家的经营需求后,传统的老板、店长、收银员等角色不足以覆盖商家角色场景。因此,在原有权限系统的基础上,增加了商家自主定义员工权限的能力,满足其细粒度管控员工权限的诉求。任何一家使用有赞开店软件经营店铺的商家,不仅能给员工赋予默认的角色,也可以实时给员工开放特定的权限、修改权限,以此保障店铺运营的安全、健康。

二、权限与权限管理

2.1 名词定义

在讲述有赞使用的权限模型之前,先介绍一下权限相关的基本概念:

  • 权限:用户可操作行为的最小单位。
  • 用户:每个用户都有唯一标识,并被授予一个或多个角色。
  • 角色:由不同的权限组合而成,最终分配给具体用户。
  • 权限管理:控制用户的权限,只能访问授权内容。

2.2 模型选择

  • ACL(Access Control List):基于用户级别的权限控制。 将系统的各种权限直接授予具体的用户。抽象来说,为每个用户维护了单独的权限列表,当需要分配权限、收回权限时,需要修改对应用户的权限信息。
  • RBAC(Role Base Access Control):基于角色级别的权限控制。 与 ACL 对比,RBAC不用给用户单个分配权限,权限与用户之前通过角色关联。通过给不同的角色分配不同的权限,只需要将用户指向对应的角色就会有对应的权限。分配权限、收回权限只需要通过修改用户的角色即可。
  • ABAC(Attribute Base Access Control):基于属性级别的权限控制。 不同于常见的将用户通过某种方式直接关联到权限的方式,ABAC 是通过动态计算一个或一组属性来是否满足某种条件来进行权限判断。

属性一般分为四类:用户属性(自然人属性,如年龄、性别等),环境属性(物理环境,如时间、地点、气候),操作属性(读、写)和对象属性(操作对象,如资金、某张图片、某个特定的页面,又称资源属性)。

因此理论上能够实现灵活的权限控制、将在权限与用户之前通过一组或多组属性实现关联,几乎能满足所有类型的需求。

基于线下经营的物理场景,有赞需要研发一套更灵活的权限管理系统,能将商家的权限需求,具象为多个不同的、支持商家自由勾选、定制的角色。从灵活性层面看,不需要对每个员工逐一做个性化定制,只需要对某一类员工做权限个性化定制(包含默认权限授权)。在权衡了权限的灵活性需求、管理维护难度、性能瓶颈之后,有赞最终选择RBAC 模型研发权限管理系统。

2.3 权限管控

抽象来看权限体系可以分为如下两类:功能权限数据权限两部分。

  • 功能权限指的是在系统中的功能可否使用,通常我们将功能权限分为查看、编辑、删除等,同时编辑、删除权限又包含了查看。通过小的权限点拆分更精细的赋予了员工能否进入某个页面查看信息、编辑信息的能力。
  • 数据权限指数据中存在的数据是否能查看,是一个更细粒度的权限。比如一个页面,不同角色查看不同的数据就需要通过数据权限控制。

管理对象维度又可以分为:店铺能力员工能力。

  • 店铺能力店铺维度的权限,比如有赞的商业化插件,可以通过店铺能力去体现。
  • 员工能力赋予员工的权限,比如收银开单、资金管理等。
  • 店铺能力优先级绝对高于员工能力,所有场景的权限判断,店铺能力必须先于员工能力。简单地说,店铺能力决定了“店铺能做什么”,员工能力决定了“用户能做什么”。

三. 权限系统1.0(SAM)

SAM平台是之前在使用的权限系统,使用的权限模型是 RBAC 模型。它的核心思路是将所有的权限结果抽象成一个 64 位的 long 型。使用方在查询某个权限点时,需将权限点与后端返回的权限集做一个位运算。

后端返回的权限数据如图所示:

//权限点
{
  "menuId": 113101101,
  "menuName": "网店查看",
  "mapBizPerms": {
    "retail": [0, 0, 1125899906842624]
  }  
}
//员工个人能力
{
  "retail": [4611686018427387903, -144115188075855873, -3]
}

业务查询具体的权限时,需要对后端返回的权限数据与权限点进行计算:

SAM 系统在设计之初,业务语言趋近于实现语言。稳定运行后,各业务在实现需求、排查问题时遇到了以下三个问题:

  • 配置难: 权限需求实现频繁依赖后端资源。在日常开发中,如果要新增权限,首先需要业务方提供一个权限需求,而权限需求有由权限描述、角色类型、店铺类型组成,后端资源到位后,实现该需求、发布至相应的测试环境,同时将权限信息同步至端侧同学,端侧同学继续完成接下来的代码适配。这条链路流程多、沟通成本高、资源依赖重、排队耗时长。
  • 排查难:原来的设计,导致端上也存在权限计算,且计算方式依赖位运算,无法直接定位问题所在。在排查权限问题时,业务往往需要先进行复杂的计算,当问题定位在权限数据出错时,需要再次依赖后端资源,进行数据的修正和发布。
  • 扩展难:权限属于中台应用,承接了微商城、零售、教育等业务方,终端类型有pc、移动端 APP、小程序、deskTop 等。SAM 系统提供的能力比较单一,无法为各端提供可定制能力。原有的菜单功能是参考 pc 设计的,无法满足移动端页面级别的的多类型组件需求。

四.机遇与挑战

随着需求增长,权限侧的资源压力开始阻塞开发进程。而权限作为基础应用,应当降低对接成本,只提供能力,而不介入业务侧的配置。改造权限系统,让权限系统能高效吞吐需求、降低资源压力、新手能“一看就会”,成为权限系统的重构方向 :

  • 业务语言“说人话”:权限应当隔离业务语言与实现语言,对接方不再需要理解晦涩的权限业务语言,“权限由业务定义”。
  • 配置方式由原来的“工具”向“操作平台”改变:权限由原来的“开发工具”平台化,并向运营平台转变,将单侧的资源压力平衡到需求方。
  • 端侧升级架构,提供更丰富的能力:提供权限解析能力,解放业务在权限判断中的生产力。

五.权限系统2.0

权限团队在 SAM 系统基础上,隔离业务语言与实现语言、转变需求处理方式,支撑有赞 APP、PC、小程序、Desktop 服务:

  • rig 系统(Rig:北欧神话中彩虹桥的守护神):添加了权限表达层,以相对友好的方式呈现给业务方,替换以往将实现逻辑直接暴露给业务方的方式。
  • 权限配置平台:权限配置平台支持业务域配置不同店铺类型的权限,支持各端根据店铺类型、平台配置不同的菜单。需求方不再依赖后端资源,开发、产品或运营可直接根据权限需求、基于店铺类型、角色、不同的平台配置权限、菜单。
  • dynamicMenu:移动端组件动态化方案。需求方在配置平台增删、编辑APP的工作台菜单后,菜单内所有的组件经过权限校验后下发,且兼容零售移动的特殊业务模式(如离线模式)。

权限后台

rig-core:权限后台系统

职责:对接上层 rig-front,以及对接业务系统(用户管理)。对外提供菜单、API、角色、用户服务,主要有以下功能:

  • 菜单服务:获取渲染菜单。
  • API 服务:API 校验。
  • 角色服务:获取角色、同步角色、增删角色等。
  • 用户服务:用户新增、更新、删除、

权限中台

rig-front:中台系统。

职责:对接上层业务方,提供 API 校验、菜单渲染、角色管理、权限管理、数据权限。

整个系统基于 spi 引擎实现业务的扩展,对于新的 namespace 或者在现有 namespace 有新的业务规则时需要开发对应的 spi 组件。

移动端

移动端权限主要提供基础的权限 API 校验, 视图能力。目前大多数场景都使用 API 校验能力,业务方根据权限做自己的处理。首页工作台使用了视图能力,根据权限渲染首页功能。

工作台架构

分为四个部分:

  • JS Engine:JS 实现的跨端计算引擎,提供统一的组件解析、权限和店铺能力解析 、移动端扩展能力解析。
  • WigetManager:负责管理移动端所有的 widget 管理、路由分发、widget 形态预处理。
  • UI 组件层:提供基础的组件如表单、网格、按钮等。
  • UI 展示层:业务根据配置,纵向展示对应的组件。
工作台实现

本文以工作台为例,介绍移动端实现原理。工作台的流程运行图如下:

零售 App 中工作台配置下发如图:

JS 引擎将原始数据筛选过滤,转换成两端用于 UI 渲染的模型。其中,menuItemType 映射成 WidgetType,用于区分 widget 类型,menuItemKey 映射成 widgetId,用于 widget 的唯一标识。由于 widget 存在于各个 module 中,所以通过路由获取 widget 实例。

@Nav("dynamicMenuWidget/UrgentNotice")
class UrgentNoticeWidgetFragment : BaseRetailWidgetFragment() {
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.home_widget_urgent_notice, container, false)
    }
    
    //数据获取成功回调
    override fun loadSuccess(data: UrgentNoticeResponse?) {}
    //数据获取失败回调
    override fun loadError(t: Throwable) {}
    //widget点击事件
    override fun onWidgetClicked() {}
}

Android 中使用 Fragment 作为 widget 的载体,通过路由库提供的方法可以非常方便的获取 Fragment 实例:

val fragment = Navigator.newInstallOrNull<BaseWidgetFragment>("dynamicMenuWidget/UrgentNotice")

一个页面会有多个 widget,考虑到 widget 刷新管理等。我们提供了一个 WidgetDelegate 用于托管页面的 widget:

class WidgetDelegate{
  val widgetMap:HashMap<String,BaseWidgetFragment>
  val activity: Activity
  var rootWidgetId: String = ""
  val children = ArrayList<WidgetDelegate>()
  var parentDelegate: WidgetDelegate? = null
  
  constructor(activity: Activity, rootWidgetId: String, parentWidgetDelegate: WidgetDelegate? = null
) {}
  constructor(fragment: BaseWidgetFragment) {
  
  /**
   * 加载widget
   * containerId:容器id
   * doAction:  业务方自定义处理数据
  */
  fun setupUI(fragmentManager: FragmentManager,@IdRes containerId: Int, beforeAction: (List<WidgetInfo>.() -> List<WidgetInfo>) = { this }) {}    
  
  /**
   * widget刷新,用于下拉刷新等
  */
  fun reload() {}  
  
  /**
   * 通过widgetId获取widget
   */
  fun findWidgetById(widgetId: String): BaseWidgetFragment? {}
}

在工作台实例化 WidgetDelegate,通过 setupUI 方法,即可完成 widget 的渲染和加载。delegate只会完成 rootWidgetId的children 的刷新,比如工作台的 delegate 处理紧急公告、实时概况、常用应用的渲染。收银开单属于常用应用的 children,所以常用应用也有一个 delegate,将工作台和常用应用的 delegate 关联起来即可。

布局方式根据传入的 container 决定,工作台为 LineearLayout,常用应用为 GridLayout。首页下拉刷新时,通过 reload方 法可对所有 widget 和 childrenDelegate 发起刷新的通知。

通常情况,我们点击一个按钮,比如收银开单,通过下发的url直接跳转到相应的页面即可。在实际的业务场景下,也需要满足各个业务方的需求。比如库存查询功能,有一个前置的接口校验,所以不能直接跳转。针对于这些情况,我们提供了一个全局事件监听的注册,当库存查询点击后,会查找有没有业务方注册的事件,如果有注册,会将事件交给业务方自行处理,实现如下:

//通过menuId注册点击事件
DynamicMenuGlabalListenerManager.addOnWidgetClickedListener("widget_finc_stock_search"){context,widgetInfo ->
  service.query(){response->
      if(response.success){
        startActivity()
      }else{
        showToast(response.msg)
      }
  }
}

优势

  • 将组件测试与权限解耦,测试不再需要回归权限相关的用例。
  • 业务组件不需要鉴权,JSEngine 进行了严密的权限校验,没有数据越权风险。
  • 除了支持权限相关的所有配置、还支持版本控制、组件的随时上下架。
  • 移动端不同平台机型上,保证了内容的完全一致性。

六.价值回顾

1.权限需求解除后端资源依赖。

业务实现权限需求升级前后对比。升级后,不再依赖测试后端资源的投入。减少不必要的人力,整个流程也得到缩减:

2.问题排查效率提高100%

端侧同学排查修复问题效率升级前后对比:

3.线上问题大幅降低:2020 H2月均线上问题环比降低76%

七.结语

我们实现的不仅仅是商家的直接诉求,而是超越商家需求,提供了一整套完备的权限解决方案。既能满足当下店铺管理的需求,也能适应未来不同店铺形态、经营方式的发展变化。

‍‍

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小草学Python和SQL 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、权限与权限管理
    • 2.1 名词定义
      • 2.2 模型选择
        • 2.3 权限管控
        • 三. 权限系统1.0(SAM)
        • 四.机遇与挑战
        • 五.权限系统2.0
          • 权限后台
            • 权限中台
              • 移动端
                • 工作台架构
                • 工作台实现
            • 六.价值回顾
            • 七.结语
            相关产品与服务
            云开发 CloudBase
            云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档