权限管理是一个几乎所有大中型 B 端系统都会涉及的重要组成部分,其目的是对整个系统进行权限控制,避免造成误操作及数据泄露等风险问题。在充分调研了商家的经营需求后,传统的老板、店长、收银员等角色不足以覆盖商家角色场景。因此,在原有权限系统的基础上,增加了商家自主定义员工权限的能力,满足其细粒度管控员工权限的诉求。任何一家使用有赞开店软件经营店铺的商家,不仅能给员工赋予默认的角色,也可以实时给员工开放特定的权限、修改权限,以此保障店铺运营的安全、健康。
在讲述有赞使用的权限模型之前,先介绍一下权限相关的基本概念:
属性一般分为四类:用户属性(自然人属性,如年龄、性别等),环境属性(物理环境,如时间、地点、气候),操作属性(读、写)和对象属性(操作对象,如资金、某张图片、某个特定的页面,又称资源属性)。
因此理论上能够实现灵活的权限控制、将在权限与用户之前通过一组或多组属性实现关联,几乎能满足所有类型的需求。
基于线下经营的物理场景,有赞需要研发一套更灵活的权限管理系统,能将商家的权限需求,具象为多个不同的、支持商家自由勾选、定制的角色。从灵活性层面看,不需要对每个员工逐一做个性化定制,只需要对某一类员工做权限个性化定制(包含默认权限授权)。在权衡了权限的灵活性需求、管理维护难度、性能瓶颈之后,有赞最终选择RBAC 模型研发权限管理系统。
抽象来看权限体系可以分为如下两类:功能权限与数据权限两部分。
从管理对象维度又可以分为:店铺能力 与 员工能力。
SAM平台是之前在使用的权限系统,使用的权限模型是 RBAC 模型。它的核心思路是将所有的权限结果抽象成一个 64 位的 long 型。使用方在查询某个权限点时,需将权限点与后端返回的权限集做一个位运算。
后端返回的权限数据如图所示:
//权限点
{
"menuId": 113101101,
"menuName": "网店查看",
"mapBizPerms": {
"retail": [0, 0, 1125899906842624]
}
}
//员工个人能力
{
"retail": [4611686018427387903, -144115188075855873, -3]
}
业务查询具体的权限时,需要对后端返回的权限数据与权限点进行计算:
SAM 系统在设计之初,业务语言趋近于实现语言。稳定运行后,各业务在实现需求、排查问题时遇到了以下三个问题:
随着需求增长,权限侧的资源压力开始阻塞开发进程。而权限作为基础应用,应当降低对接成本,只提供能力,而不介入业务侧的配置。改造权限系统,让权限系统能高效吞吐需求、降低资源压力、新手能“一看就会”,成为权限系统的重构方向 :
权限团队在 SAM 系统基础上,隔离业务语言与实现语言、转变需求处理方式,支撑有赞 APP、PC、小程序、Desktop 服务:
rig-core:权限后台系统
职责:对接上层 rig-front,以及对接业务系统(用户管理)。对外提供菜单、API、角色、用户服务,主要有以下功能:
rig-front:中台系统。
职责:对接上层业务方,提供 API 校验、菜单渲染、角色管理、权限管理、数据权限。
整个系统基于 spi 引擎实现业务的扩展,对于新的 namespace 或者在现有 namespace 有新的业务规则时需要开发对应的 spi 组件。
移动端权限主要提供基础的权限 API 校验, 视图能力。目前大多数场景都使用 API 校验能力,业务方根据权限做自己的处理。首页工作台使用了视图能力,根据权限渲染首页功能。
分为四个部分:
本文以工作台为例,介绍移动端实现原理。工作台的流程运行图如下:
零售 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)
}
}
}
优势
1.权限需求解除后端资源依赖。
业务实现权限需求升级前后对比。升级后,不再依赖测试后端资源的投入。减少不必要的人力,整个流程也得到缩减:
2.问题排查效率提高100%
端侧同学排查修复问题效率升级前后对比:
3.线上问题大幅降低:2020 H2月均线上问题环比降低76%
我们实现的不仅仅是商家的直接诉求,而是超越商家需求,提供了一整套完备的权限解决方案。既能满足当下店铺管理的需求,也能适应未来不同店铺形态、经营方式的发展变化。
本文分享自 小草学Python和SQL 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!