文 | 毛成光、马纯洁 on 零售php
有赞做为一个商家服务公司,经过产品和服务,帮助互联网时代的生意人成功。在新零售的浪潮下,有赞零售为商家提供不一样规模的门店和网店经营解决方案,帮助零售商家们快速进入新零售时代。与传统网上商城场景不一样,零售面对着全新的业务场景和难题,一家运转成熟的新零售店铺,一般须要包括老板、店长、客服、收银员、核销员、仓管、财务等十余个不一样能力的角色分工、搭配。摆在零售商家们眼前的一大难题是,如何优雅的管理各个员工,自由分配角色,无痛又润滑地解决员工角色管理问题。在充分分析零售行业业务场景,员工角色管理方案的不断探索讨论后,权限系统 SAM(Security Access Manager)应运而生,SAM 是有赞零售在员工角色权限管理道路上探索的里程碑,支持着零售 PC、App 和 Pad 产品的权限业务,任何一家使用了有赞零售的零售店均可以经过 SAM 权限系统提供的服务来灵活的给店里员工灵活分配角色,责任到人,以此提升店铺运转效率;支撑零售业务的同时,抽象出了一套权限管理框架,对其余业务线产品(微商城)进行一样支持。node
在介绍 SAM 系统以前,首先以几个案例来理解权限系统的概念和设计。python
计算机世界中的许多事物是现实世界的一个阴影,现实中所见的许多模式/概念在计算机世界里都能找到。曾记否,QQ 里隐身对她可见,怕她看不见,下线又上线,却依旧被视而不见;曾记否,亲密无间的恋人们,分手后变成了最熟悉的陌生人,悲痛伤心之余,微信、电话、 QQ 拉黑。这些案例,都是计算机权限系统对现实世界的一个映射,你对女神隐身可见,其实是赋予了她能够看到你的隐身状态(真实状态)的权限,固然你也赋予了人家伤害你的权限;恋人们把对方拉到了黑名单用户组,这样一来,他们就看不见相互动态,成为最熟悉的陌生人;今后,从你的全世界路过。web
上面例子,咱们能够抽象出这样的模式:“ Who 对 What(Which)进行 How 的操做” 。例如,恋人们的例子,在你拉黑对方后,在朋友圈中你(Who)将看不到(How)对方的消息(What)。这是一个经典的 RBAC(基于角色的权限访问控制)权限模型。RBAC 认为权限受权其实是 Who、What、How 的问题。在 RBAC 模型中,Who、What、How 构成了访问权限三元组,也就是“Who(权限的拥用者或主体)对 What(Which)(权限针对的对象或资源)进行 How(具体的权限)的操做”。数据库
RBAC 模型引入了“角色”的概念。所谓“角色”就是一个或一群用户在系统中可执行操做的集合,它是一个用户的集合,又是一个受权许可的集合。经过将角色指派给用户,为角色赋予权限的方式,使用户和权限经过角色间接相联系。RBAC 基本模型如图所示:后端
在 RBAC 中,用户与角色之间、角色与权限之间都是多对多的关系。会话是一个用户对多个角色的映射,此时的用户权限能够为激活角色权限的并集。RBAC 对资源受权管理过程分为两个部分,首先实现访问权限与角色相关联,而后再实现角色与用户相关联,从而实现了用户与访问权限的逻辑分离。api
RBAC 模型不一样于强制存取控制以及自由选定存取控制直接赋予使用者权限,是将权限赋予角色。在 RBAC 中,权限与角色相关联,用户经过成为适当角色成员而获得这些角色的权限,角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据须要而从某角色中回收。RBAC 相对于传统访问控制更为中性且更具灵活性的存取控制技术。从一家零售店铺员工角色管理角度看,设置角色是为了完成各类工做而创造,员工则根据它的责任和资格来被指派相应的角色,员工应该能够很容易地从一个角色被指派到另外一个角色。所以,零售选择了基于 RBAC 模型来实现权限系统解决商家们管理员工角色问题。缓存
依据 RBAC 模型思想,SAM 权限系统业务模型设计为员工管理和权限管理两部分,员工管理主要指管理员工以及为员工指派角色,权限管理主要指管理菜单、页面、按钮、API 等资源,经过定义最基本的业务功能点做为权限点,实现管理角色对资源主体的请求,构成“用户-角色-权限-资源”的受权模型。安全
下面是 SAM 权限系统模型中的一些通用语言:微信
在传统的 RBAC 模型中,一般经过一张关系表来保存角色与权限集的对应关系,实现权限与角色相关联。能够预见的是,随着零售业务的不断发展会积累下不可胜数的功能点,致使关联表的数据极难维护和使用。SAM 权限系统利用进制转换的策略解决了这个问题 ,同时提升了存储效率以及权限断定效率。一个基本类型为 Long 的十进制数字,它也能够看作是由 64 位 0 或 1 组成的二进制。在 SAM 系统模型设计中,每个功能点定义为一个权限点,该权限点由 idx 和 pos 两个属性确保是全局惟一的权限点。idx 表示第几个 Long 型空间,pos 表示 Long 型对应的二进制数中所处的位置,64 位长度便可表明 64 个不一样能功能点。当 64 位满时没法再容放更多的功能点,这时 idx 属性会自增,从新申请一个 Long 型空间。如此一个 64 位的 Long 数字,经过 0 或 1 的组合,便可表示最多对 64 个不一样的功能点所拥有权限的状态描述。
例如:权限集{1}表示拥有 idx=0, pos=0 对应功能点的权限,权限集{-1,1}表示拥有idx=0,pos∈[0,1,2,..,63]与 idx=1,pos=0 对应功能点的权限。
SAM 权限系统将资源与所表明的功能点的关联关系经过进制的方式管理起来,采用计算机进制的思想,抽象出功能集换算公式来完成资源与二进制之间的映射,以及角色与二进制的映射。
权限集换算公式:
{(idx0,pos0),(idx0,pos1)…(idxN,posM)} => {Long0,Long1…LongN}
SAM 权限系统一样经过进制思想实现“ Who 对 What 进行了 How 的操做”,角色请求某个资源(菜单/API)时,经过权限校验计算公式——进制按位“与”运算操做的思想(见下)得出该角色是否拥有访问资源的权限。采用进制来实现运算,权限断定的效率会变得更加的高效。例如,一个仓管在点击一个商品库存菜单时,背后的权限校验计算公式,实际上是将角色的权限集与资源的权限集进行按位与计算,任意一对序号为 idx 的 Long 算得不为 0,即两集合有公共的功能集,认为该角色拥有对资源访问的权限。
权限校验计算公式:
{Long0,Long1…LongN} & {Long0,Long1…LongM}
SAM 权限系统模型的实现遵循 RBAC 模型中的最小权限原则,责任分离原则和数据抽象原则三大原则,经过最小权限原则能够将角色配置成其完成任务所须要的最小的功能集;有了责任分离原则能够经过调用相互独立互斥的角色来共同完成敏感的任务而体现,好比要求一个仓管和商品管理员共同参与一个商品。数据抽象则能够经过权限的抽象来体现,如仓管操做商品发货,库存管理等抽象权限,而不用操做系统提供的典型的读、写、执行权限。
零售经过 PC、App 和 Pad 来知足不一样商家的终端需求,所以 SAM 权限系统须要知足零售不一样客户端权限业务场景,同时也要支持微商城产品权限业务。SAM 权限系统采用微服务的方式对外提供服务,采用分布式分层架构实现,主要包括客户端和服务端两部分,客户端以轻量的方式嵌入在业务系统,提供给不一样业务系统实现角色访问资源的控制;服务端经过提供 Dubbo 服务,Nova 服务跟客户端进行交互。服务端主要对员工,菜单,角色,API,功能点进行数据管理。SAM 做为基础服务,天天的请求量巨大,经过 Redis 缓存来解决性能问题,选用 Druid 做为数据库链接池,管理着数据库的链接以及释放。同时,经过对接天网监控平台来观察系统运行状态,提升系统的稳定性。
有赞零售系统基于 SAM 实现的角色对于资源的访问控制主要是 API 校验和菜单渲染,任何一家零售店登入有赞零售系统后,点击页面中的某一个菜单或者页面元素(按钮,连接…),都会进行菜单渲染以及 API 接口的校验。因为两部分调用量巨大,同时不一样的客户端请求量不一样,防止相互之间干扰,所以将菜单渲染,API校验等能力在不一样的客户端中各自实现。
SAM 经过客户端的方式进行接入,菜单渲染在客户端一侧进行。目前 SAM 已经提供了 php/node js 两套客户端,供 web 层进行接入和渲染。
菜单渲染的过程能够分为三点:
1、结点定位
按照系统功能的划分,菜单一般以一棵树的形式进行展示。以零售 PC 后台为例,全部在页面中展现的元素,都认为是一种菜单,这样的菜单元素包括:菜单、页面、按钮。在后台访问时,用户停留的菜单一般是页面,页面有一个全局惟一的属性:URL,往上:能够经过父菜单找到根结点,往下,页面下可能包含一些子菜单——按钮。所以 SAM 只须要根据当前请求的 URL,便可在后台菜单树中定位到惟一的页面菜单,同时得到该菜单的结点路径以及拥有的按钮。
2、权限计算
咱们已经得到了用户的角色权限和完整的菜单树,根据每一个菜单结点的权限集,能够计算出当前用户对结点的访问权。根据计算结果,客户端对菜单能够进行区分渲染,好比:用户经过拼 URL 访问一个无权限页面时会提示非法,无权限访问的菜单和按钮会自动置灰不可点击。
3、属性传递
默认菜单不具有 URL 属性。菜单的 URL 属性经过子菜单的 URL 传递生成,SAM 会选择第一个有权限的子菜单的 URL 做为父结点的属性,并逐级传递到一级菜单。
零售系统中除了菜单外,API 是另外一种被请求的资源类型。API 校验是除了菜单渲染外另外一道权限控制的保障。经过卡门( API 网关)的 API 请求转发到具体业务系统时,嵌入在业务系统中的 SAM API 校验客户端会首先经过上面的权限校验计算公式对该角色是否具备权限访问这个 API 进行断定,若权限校验经过则执行后面业务逻辑。
具体流程以下图所示
API 权限校验的伪代码实现:
#权限不经过错误码提示信息 AUTHPERM_ERROR(231000401,"您没有权限执行该操做!") # 织入点 @Before("@annotation(com.youzan.sam.common.Auth)") # 切面处理方法 def handle(JoinPoint pjp): # 能够启动时或者运行时控制该开关是否对API进行权限校验 if(!enable): return # 权限校验结果包装对象 def pass=checkPermission() # 权限校验执行成功 if (pass.isSuccess()): # 权限校验经过 if(pass.getData().get("isSuccess")): return # 权限校验不经过 else: throw new BusinessException(AUTHPERM_ERROR.getCode,AUTHPERM_ERROR.getMessage()); # 权限校验执行失败 else: throw BusinessException(pass.getCode(), pass.getMessage()) # 权限校验方法 def checkPermission(): # 判断是否须要走权限校验,对于某些内部调用能够直接跳过 {...} # 获取卡门(API网关)隐式参数,运用了dubbo的隐式传参的能力 def kdt_id=RpcContext.getContext().getAttachment(Constants.KDT_ID_KEY) def admin_id=RpcContext.getContext().getAttachment(Constants.ADMIN_ID_KEY) def service = RpcContext.getContext().getAttachment(Constants.SERVICE_KEY) def method = RpcContext.getContext().getAttachment(Constants.METHOD_KEY) def version = RpcContext.getContext().getAttachment(Constants.VERSION_KEY) # 上述参数的校验 {...} # 经过StaffPermServiceProxy获取角色的权限集 def staffPerm=StaffPermServiceProxy.getStaffPerms(adminId, kdtId) # 经过APIPermServiceProxy获取API的权限集 def apiPerm=APIPermServiceProxy.getServicePerms(service, version, method) # 运用权限校验计算公式断定该角色是否能够访问此API {...} # 返回结果 return pass
API 权限校验流程能够总结以下:
产品在分析完需求后,将需求交由开发去完成。SAM 权限系统支撑着零售业务的同时,也支撑着微商城业务。 零售各个模块就有不一样的产品支撑着,为了更好的知足服务商家的需求,以及方便产品们的分析。SAM 权限系统能够抽象成以下模型,商家和产品能够从各自不一样的视角,去对接 SAM 权限系统。例如,下图所示商家想要一个运营的角色须要有新建商品,以及查看订单的能力,同时须要一个收银员只有查看订单的能力。产品从本身的设计角度分析,对应的就是商品管理,订单管理的模块,对应的模块下有对应的商品,订单菜单,最后将角色的权限体如今页面元素和 API 上,例如新建商品的按钮,以及查看订单的按钮会呈现不一样的渲染样式;按钮触发对应的是与后端交互的不一样 API,不一样的角色具备 API 的不一样执行能力。
在了解商家需求后,零售提供了 8 大默认角色来支持单店版的员工角色问题。零售业务错综复杂,默认角色不少时候并不能对付全部场景,如今一些自定义角色已经在某些零售店使用。将来自定义角色将全线支持各个商家,定制任意权限的任意角色。
有些零售商家为了缩减人力成本,一个员工经常担任多个角色,所以须要提供一个员工多角色的能力。零售业务已经在使用多角色的能力。
零售中台是有赞零售的一个旗舰型产品,旨在为商家提供一个覆盖线上多渠道线下多门店的全渠道解决方案,并利用数据化运营思路帮助商家拉新获客、提升复购。其业务形态很是复杂,涉及到多种角色和权限的组合,并且每一个商家可能存在一些个性化需求,如何提供灵活的适配能力是 SAM 系统的一个挑战。
过去后台功能的发布上线,每每是由发布系统控制,发布则功能即刻上线,一旦发现故障立时回滚。SAM 经过菜单管理,能够实时控制线上的任意菜单、页面和按钮的渲染状态,从容地上下线页面和功能。
SAM 做为零售以及其余业务的公共基础组件,须要打形成一个高可用,高性能,易扩展,可伸缩且安全的系统。随着业务的不断接入,经过对系统的不断改造来支撑业务的不断发展。
权限系统目前归属有赞零售技术团队,对外开放权限接入和员工服务化能力。目前团队业务发展迅速,HC 持续开放中,期待更多有志之士加入搞事情。