文 | 毛成光、馬純潔 on 零售
有贊作為一個商家服務公司,通過產品和服務,幫助網際網路時代的生意人成功。在新零售的浪潮下,有贊零售為商家提供不同規模的門店和網店經營解決方案,幫助零售商家們快速進入新零售時代。與傳統網上商城場景不同,零售面對著全新的業務場景和難題,一家運轉成熟的新零售店鋪,通常需要包括老闆、店長、客服、收銀員、核銷員、倉管、財務等十餘個不同能力的角色分工、搭配。擺在零售商家們眼前的一大難題是,如何優雅的管理各個員工,自由分配角色,無痛又潤滑地解決員工角色管理問題。在充分分析零售行業業務場景,員工角色管理方案的不斷探索討論後,許可權系統 SAM(Security Access Manager)應運而生,SAM 是有贊零售在員工角色許可權管理道路上探索的里程碑,支援著零售 PC、App 和 Pad 產品的許可權業務,任何一家使用了有贊零售的零售店都可以通過 SAM 許可權系統提供的服務來靈活的給店裡員工靈活分配角色,責任到人,以此提高店鋪運轉效率;支撐零售業務的同時,抽象出了一套許可權管理框架,對其他業務線產品(微商城)進行同樣支援。
在介紹 SAM 系統之前,首先以幾個案例來理解許可權系統的概念和設計。
計算機世界中的許多事物是現實世界的一個陰影,現實中所見的許多模式/概念在計算機世界裡都能找到。曾記否,QQ 裡隱身對她可見,怕她看不見,下線又上線,卻依舊被視而不見;曾記否,親密無間的戀人們,分手後變成了最熟悉的陌生人,悲痛傷心之餘,微信、電話、 QQ 拉黑。這些案例,都是計算機許可權系統對現實世界的一個對映,你對女神隱身可見,實際上是賦予了她可以看到你的隱身狀態(真實狀態)的許可權,當然你也賦予了人家傷害你的許可權;戀人們把對方拉到了黑名單使用者組,這樣一來,他們就看不見相互動態,成為最熟悉的陌生人;從此,從你的全世界路過。
RBAC
上面例子,我們可以抽象出這樣的模式:“ Who 對 What(Which)進行 How 的操作” 。例如,戀人們的例子,在你拉黑對方後,在朋友圈中你(Who)將看不到(How)對方的訊息(What)。這是一個經典的 RBAC(基於角色的許可權訪問控制)許可權模型。RBAC 認為許可權授權實際上是 Who、What、How 的問題。在 RBAC 模型中,Who、What、How 構成了訪問許可權三元組,也就是“Who(許可權的擁用者或主體)對 What(Which)(許可權針對的物件或資源)進行 How(具體的許可權)的操作”。
RBAC 模型引入了“角色”的概念。所謂“角色”就是一個或一群使用者在系統中可執行操作的集合,它是一個使用者的集合,又是一個授權許可的集合。通過將角色指派給使用者,為角色賦予許可權的方式,使使用者和許可權通過角色間接相聯絡。RBAC 基本模型如圖所示:
在 RBAC 中,使用者與角色之間、角色與許可權之間都是多對多的關係。會話是一個使用者對多個角色的對映,此時的使用者許可權可以為啟用角色許可權的並集。RBAC 對資源授權管理過程分為兩個部分,首先實現訪問許可權與角色相關聯,然後再實現角色與使用者相關聯,從而實現了使用者與訪問許可權的邏輯分離。
許可權系統 SAM
SAM 許可權系統模型設計
RBAC 模型不同於強制存取控制以及自由選定存取控制直接賦予使用者許可權,是將許可權賦予角色。在 RBAC 中,許可權與角色相關聯,使用者通過成為適當角色成員而得到這些角色的許可權,角色可依新的需求和系統的合併而賦予新的許可權,而許可權也可根據需要而從某角色中回收。RBAC 相對於傳統訪問控制更為中性且更具靈活性的存取控制技術。從一家零售店鋪員工角色管理角度看,設定角色是為了完成各種工作而創造,員工則根據它的責任和資格來被指派相應的角色,員工應該可以很容易地從一個角色被指派到另一個角色。因此,零售選擇了基於 RBAC 模型來實現許可權系統解決商家們管理員工角色問題。
依據 RBAC 模型思想,SAM 許可權系統業務模型設計為員工管理和許可權管理兩部分,員工管理主要指管理員工以及為員工指派角色,許可權管理主要指管理選單、頁面、按鈕、API 等資源,通過定義最基本的業務功能點作為許可權點,實現管理角色對資源主體的請求,構成“使用者-角色-許可權-資源”的授權模型。
下面是 SAM 許可權系統模型中的一些通用語言:
- 員工:角色的載體,許可權的實行者
- 角色:角色是許可權集進一步對映。業務系統可動態管理角色,各業務為方便使用者使用可提供給預設角色列表,滿足不同的員工許可權
- 許可權點:全域性唯一的用來表示某一個功能點對應的許可權的狀態
- 功能點:邏輯上定義的用來描述系統資源的最小基本單位,每一個功能點都對應唯一一個許可權點
- 功能集(許可權集):即功能點的集合,有一組功能點按照特定格式進行組合
- API:請求系統資源的通道和動作,擁有功能集屬性
- 選單:將系統資源組織後展示給請求者的入口,擁有功能集屬性
- 頁面:被當做一種特殊的選單,擁有 URL 屬性
- 按鈕:頁面中更細粒度的資源入口,被當作一種特殊的選單
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 模型中的最小許可權原則,責任分離原則和資料抽象原則三大原則,通過最小許可權原則可以將角色配置成其完成任務所需要的最小的功能集;有了責任分離原則可以通過呼叫相互獨立互斥的角色來共同完成敏感的任務而體現,比如要求一個倉管和商品管理員共同參與一個商品。資料抽象則可以通過許可權的抽象來體現,如倉管操作商品發貨,庫存管理等抽象許可權,而不用作業系統提供的典型的讀、寫、執行許可權。
SAM 許可權系統架構
零售通過 PC、App 和 Pad 來滿足不同商家的終端需求,因此 SAM 許可權系統需要滿足零售不同客戶端許可權業務場景,同時也要支援微商城產品許可權業務。SAM 許可權系統採用微服務的方式對外提供服務,採用分散式分層架構實現,主要包括客戶端和服務端兩部分,客戶端以輕量的方式嵌入在業務系統,提供給不同業務系統實現角色訪問資源的控制;服務端通過提供 Dubbo 服務,Nova 服務跟客戶端進行互動。服務端主要對員工,選單,角色,API,功能點進行資料管理。SAM 作為基礎服務,每天的請求量巨大,通過 Redis 快取來解決效能問題,選用 Druid 作為資料庫連線池,管理著資料庫的連線以及釋放。同時,通過對接天網監控平臺來觀察系統執行狀態,提高系統的穩定性。
有贊零售系統基於 SAM 實現的角色對於資源的訪問控制主要是 API 校驗和選單渲染,任何一家零售店登入有贊零售系統後,點選頁面中的某一個選單或者頁面元素(按鈕,連結…),都會進行選單渲染以及 API 介面的校驗。由於兩部分呼叫量巨大,同時不同的客戶端請求量不同,防止相互之間干擾,因此將選單渲染,API校驗等能力在不同的客戶端中各自實現。選單渲染
SAM 通過客戶端的方式進行接入,選單渲染在客戶端一側進行。目前 SAM 已經提供了 php/node js 兩套客戶端,供 web 層進行接入和渲染。 選單渲染的過程可以分為三點:
一、結點定位
按照系統功能的劃分,選單通常以一棵樹的形式進行展現。以零售 PC 後臺為例,所有在頁面中展示的元素,都認為是一種選單,這樣的選單元素包括:選單、頁面、按鈕。在後臺訪問時,使用者停留的選單通常是頁面,頁面有一個全域性唯一的屬性:URL,往上:可以通過父選單找到根結點,往下,頁面下可能包含一些子選單——按鈕。因此 SAM 只需要根據當前請求的 URL,即可在後臺選單樹中定位到唯一的頁面選單,同時獲得該選單的結點路徑以及擁有的按鈕。
二、許可權計算
我們已經獲得了使用者的角色許可權和完整的選單樹,根據每個選單結點的許可權集,可以計算出當前使用者對結點的訪問權。根據計算結果,客戶端對選單可以進行區分渲染,比如:使用者通過拼 URL 訪問一個無許可權頁面時會提示非法,無許可權訪問的選單和按鈕會自動置灰不可點選。
三、屬性傳遞
預設選單不具備 URL 屬性。選單的 URL 屬性通過子選單的 URL 傳遞生成,SAM 會選擇第一個有許可權的子選單的 URL 作為父結點的屬性,並逐級傳遞到一級選單。
API 許可權校驗
零售系統中除了選單外,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 許可權校驗流程可以總結如下:
- 業務方在對應需要許可權校驗的 API 上標註 @Auth 註解,Spring 框架會在初始化建立業務 bean 的時候,掃描該 bean 是否有 @Auth 註解標註的方法,對於有 @Auth 註解標註的,會建立代理類,然後會將該許可權切面織入到代理類中;
- 業務呼叫有 @Auth 註解標註的方法時,會執行該許可權校驗切面邏輯,首先檢查許可權校驗開關,判斷是否需要許可權校驗,該開關可以在執行時動態設定;
- 如果需要,再呼叫 AuthService 的許可權校驗方法,AuthService 會根據店鋪 ID 與使用者 ID 從 SAM 服務端獲取員工角色許可權資訊,根據卡門(API 閘道器)隱式引數中 service,method,version 去 SAM 服務端獲取對應 API 許可權(相對於在對應 API 上直接標註許可權點,這種方式更加的靈活,而且可以隨著業務 API 版本的升級,進行很方便的升級,同時結合卡門( API 閘道器)可以對 API 進行分流,不同的商家可以對應不同 API 的許可權校驗。
- 在獲取到角色許可權集和 API 許可權集後,基於上面的角色與許可權校驗邏輯進行許可權校驗。校驗通過,則正式發起 API 請求。校驗不過,則提示無許可權。
SAM許可權系統抽象模型
產品在分析完需求後,將需求交由開發去完成。SAM 許可權系統支撐著零售業務的同時,也支撐著微商城業務。 零售各個模組就有不同的產品支撐著,為了更好的滿足服務商家的需求,以及方便產品們的分析。SAM 許可權系統可以抽象成如下模型,商家和產品可以從各自不同的視角,去對接 SAM 許可權系統。例如,下圖所示商家想要一個運營的角色需要有新建商品,以及檢視訂單的能力,同時需要一個收銀員只有檢視訂單的能力。產品從自己的設計角度分析,對應的就是商品管理,訂單管理的模組,對應的模組下有對應的商品,訂單選單,最後將角色的許可權體現在頁面元素和 API 上,例如新建商品的按鈕,以及檢視訂單的按鈕會呈現不同的渲染樣式;按鈕觸發對應的是與後端互動的不同 API,不同的角色具有 API 的不同執行能力。
未來展望
自定義角色
在瞭解商家需求後,零售提供了 8 大預設角色來支援單店版的員工角色問題。零售業務錯綜複雜,預設角色很多時候並不能對付所有場景,現在一些自定義角色已經在某些零售店使用。未來自定義角色將全線支援各個商家,定製任意許可權的任意角色。
多角色
有些零售商家為了縮減人力成本,一個員工常常擔任多個角色,因此需要提供一個員工多角色的能力。零售業務已經在使用多角色的能力。
零售中臺的支援
零售中臺是有贊零售的一個旗艦型產品,旨在為商家提供一個覆蓋線上多渠道線下多門店的全渠道解決方案,並利用資料化運營思路幫助商家拉新獲客、提高復購。其業務形態非常複雜,涉及到多種角色和許可權的組合,而且每個商家可能存在一些個性化需求,如何提供靈活的適配能力是 SAM 系統的一個挑戰。
自定義選單
過去後臺功能的釋出上線,往往是由釋出系統控制,釋出則功能即刻上線,一旦發現故障立時回滾。SAM 通過選單管理,可以實時控制線上的任意選單、頁面和按鈕的渲染狀態,從容地上下線頁面和功能。
技術改造
SAM 作為零售以及其他業務的公共基礎元件,需要打造成一個高可用,高效能,易擴充套件,可伸縮且安全的系統。隨著業務的不斷接入,通過對系統的不斷改造來支撐業務的不斷髮展。
結語
許可權系統目前歸屬有贊零售技術團隊,對外開放許可權接入和員工服務化能力。目前團隊業務發展迅速,HC 持續開放中,期待更多有志之士加入搞事情。