一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

[七年技術總結(jié)系列][理論篇]-RBAC權(quán)限模型由淺入深

 小世界的野孩子 2021-07-30

權(quán)限部分將分兩章介紹,第一章由淺入深介紹權(quán)限理論知識及應用,第二章介紹具體實現(xiàn)。后期再講述中間件的使用時,還會插入一些權(quán)限內(nèi)容,本質(zhì)上屬于中間件的應用。

權(quán)限模塊是業(yè)務系統(tǒng)最常見、最基本的子集。本章假定了一個系統(tǒng)從最初簡單的需求到逐漸成熟且完善的權(quán)限體系的實現(xiàn)過程。

閱讀本章預計花費20分鐘。

1. 最簡單的權(quán)限模型

業(yè)務系統(tǒng)初期,需求簡單,對于權(quán)限的內(nèi)容本身并不復雜,我們假設權(quán)限部分僅有這樣簡單的需求:

能給用戶賦予數(shù)據(jù)的增、刪、改、查四種權(quán)限

分析此需求,權(quán)限的主體為用戶,權(quán)限的內(nèi)容有多種,關系為M - M,具體為:
用戶模型:

public class User
{
    public int UserId{ get; set; }
    public string UserName { get; set; }
}

用戶表Auth_User

字段 類型 說明
*UserId int 用戶ID
UserName varchar 用戶名
... ... ...

權(quán)限枚舉:

[Flags]
public enum Permission
{
    Add = 1,
    Update = 2,
    Delete = 4,
    Select = 8
}

權(quán)限表 Auth_Permission

字段 類型 說明
*PermissionId int 權(quán)限ID
Permission varchar 權(quán)限內(nèi)容

用戶-權(quán)限關系表 Auth_UserPermission

字段 類型 說明
*UserId int 用戶ID
*PermissionId int 權(quán)限ID

假如一個用戶有增、改兩種權(quán)限,那么關系表(Auth_UserPermission)可以存儲為:

UserId Permission
1 1
1 2

于是對于權(quán)限的基本操作我們可以進行歸納:

  • 授權(quán):INSERT 權(quán)限表 (用戶ID,權(quán)限的具體值)
  • 校權(quán):EXISTS 權(quán)限表 UserID==用戶ID AND Permission==要判斷權(quán)限的具體值

我們留意到對于Permission的枚舉定義,值使用了對2的冪運算的值:

冪運算 十進制 二進制 十六進制
2^0 1 0001 0x01
2^1 2 0010 0x02
2^2 4 0100 0x04
2^3 8 1000 0x08

這么定義是有好處的,對于Auth_UserPermission的表存儲可以節(jié)省存儲空間,并且程序便于處理,譬如:
如果UserId=1的用戶擁有Add、Select權(quán)限,Auth_UserPermission表原本應該存儲兩條記錄:

  • (1,1)
  • (1,8)

現(xiàn)在,可以考慮更簡單的存儲方式

  • (1,9)

這表示:
Permission.Add | Permission.Select
等價于
1 按位或 8 ( 1 | 8 )
等價于
9

而對于權(quán)限的判斷,則使用存儲的權(quán)限值按位與要進行校權(quán)的值是否等于要進行校權(quán)的值來判斷
譬如判斷用戶是否擁有Delete權(quán)限,則使用9按位與4是否等于4來進行判斷,用C#的三目運算來表示為:

9 & 4 == 4 ? "有權(quán)限":"無權(quán)限"

這樣被標記有Flags特性的枚舉在.Net框架中遍布各種基礎類庫,譬如反射中的BindFlags枚舉。本身屬于基礎知識,由于不常應用所以容易被忽視,在權(quán)限中屬于應用小技巧。還有人質(zhì)疑這么存儲會有性能問題,在后面章節(jié)講到優(yōu)化時,再行討論。

于是我們對使用了小技巧的新的權(quán)限基本控制再次進行歸納:

  • 授權(quán):INSERT 權(quán)限表(用戶ID,所有擁有權(quán)限的按位或值)
  • 校權(quán):EXISTS 權(quán)限表(UserID == 用戶ID AND Permission & 要判斷權(quán)限的具體值 == 要判斷權(quán)限的具體值)

2. 基于角色的基本權(quán)限控制

隨著業(yè)務系統(tǒng)的發(fā)展,業(yè)務系統(tǒng)有了第一次升級機會,并附帶了一個新的權(quán)限需求:

系統(tǒng)需要滿足一類職位的人擁有相同的權(quán)限

按照第一節(jié)的內(nèi)容,這個需求其實不用做任何變化一樣可以滿足,但是問題在于負責授權(quán)的人“太累了”,對于每一個用戶,我們可能都要做一遍授權(quán)的操作。
為了解決這個問題,我們引入角色這一基本單元,角色是一種抽象,可以具體到業(yè)務場景的類似職位、身份等概念。

角色模型設計:

public class Role
{
    public int RoleId { get;set; }
    public string RoleName { get;set; }
}

角色表設計Auth_Role:

字段 類型 說明
*RoleId int 角色ID
RoleName varchar 角色名稱

基于角色的基本權(quán)限控制的原則是:

  1. 簡化用戶權(quán)限的操作;
  2. 權(quán)限操作的對象從用戶變更為角色;
  3. 不能對單一用戶做權(quán)限操作,僅對角色做權(quán)限操作,每個需要權(quán)限的用戶,都擁有至少一個角色;

角色與用戶的抽象關系表現(xiàn)為M-M,這表示:

  • 一個用戶可以擁有多個角色;
  • 一個角色下有多個用戶;

具體到業(yè)務可以是一個人可以有多個職位;一個職位下有多個人;
針對此設計,我們需要做以下操作:

  1. 從系統(tǒng)中刪除掉原來的Auth_UserPermission關系;
  2. 新增Auth_UserRole(UserId,RoleId)的關系;
  3. 新增Auth_RolePermission(RoleId,Permission)的關系;

假定業(yè)務系統(tǒng)有這樣的職位列表:

RoleId RoleName
1 總裁
2 開發(fā)總監(jiān)

假設用戶ID等于1001的用戶職位為總裁兼開發(fā)總監(jiān),那么關系表Auth_UserRole可以存儲為:

UserId RoleId
1001 1
1001 2

業(yè)務約定:總裁有增、刪、改、查四個權(quán)限,開發(fā)總監(jiān)則有增、查兩個權(quán)限,那么關系表Auth_RolePermission可以存儲為:

RoleId Permission
1 15( = 1 | 2 | 4 | 8 )
2 9

我們對給予角色的基本權(quán)限控制操作再次歸納為:

  • 授權(quán):給角色添加權(quán)限(INSERT Auth_RolePermission),給用戶添加角色(INSERT Auth_UserRole)
  • 校權(quán):應當是拿出用戶所有的角色,并再次拿出這些角色的權(quán)限做并集,并DISTINCT 權(quán)限并集為權(quán)限集合,判斷權(quán)限集合是否含有需要校權(quán)的權(quán)限

3. 基于角色并含有用戶組概念的權(quán)限控制

春去秋來,業(yè)務系統(tǒng)迎來了第二次升級機會,并包含以下新的權(quán)限需求:

所有部門的開發(fā)崗位擁有相同的增、查權(quán)限

基于第二節(jié)的系統(tǒng)升級,解決此需求我們會有臨時的做法:做一個角色,給所有開發(fā)崗的同事賦予這個角色。

這樣的臨時做法的確解決了我們的問題,但這里有幾個問題,函待解決:

  1. 系統(tǒng)沒有部門的對應抽象;
  2. 一旦其中一個部門的開發(fā)崗同事?lián)碛械臋?quán)限有變動,我們需要新建角色,并重新授權(quán);

針對此兩個問題,我們引入一個新的模型:用戶組(UserGroup),用戶組的概念在業(yè)務系統(tǒng)中,可以具體為:部門、小組、團隊等

用戶組模型設計:

public class UserGroup
{
    public int UserGroupId { get; set; }
    public int ParentId { get;set; } //留意此字段,將在本節(jié)末尾闡述
    public string UserGroupName { get; set; }
}

用戶組表Auth_UserGroup設計:

字段 類型 說明
*UserGroupId int 部門ID
ParentId int 上級部門ID
UserGroupName varchar 部門名稱

基于角色并含有用戶組概念的權(quán)限控制有以下特點:

  1. 再次簡化了用戶權(quán)限的操作;
  2. 用戶可以擁有角色;用戶組也可以擁有角色;
  3. 權(quán)限的操作對象依舊為角色,不可對用戶、用戶組進行權(quán)限操作;

用戶與用戶組的關系表現(xiàn)為多對多,這表示一個用戶可以屬于多個用戶組,一個用戶組下可以有多個用戶,具體到業(yè)務可以描述為:一個人可以在多個部門,一個部門下可以有多個人;

用戶組與角色的關系表現(xiàn)為多對多,這表示一個用戶組的所有用戶可以擁有相同的多個角色,一個角色下有多個用戶組,具體到業(yè)務可以描述為:同一個部門的人可以擁有多個相同的職位;

為了實現(xiàn)此設計,我們需要做以下新的操作:

  1. 新增Auth_UserUserGroup關系;
  2. 新增Auth_UserGroupRole關系;

假設系統(tǒng)擁有這樣的部門列表:

UserGroupId UserGroupName
1 總裁辦
2 前端開發(fā)部
3 中臺開發(fā)部
4 人力資源部
5 保安部

假設用戶ID為1101的用戶既是前端開發(fā)部的開發(fā)總監(jiān),又是中臺開發(fā)部的開發(fā)總監(jiān);中臺開發(fā)部、前端開發(fā)部的所有同事本質(zhì)都是開發(fā),且所有開發(fā)部的同事都有增、查的權(quán)限,那么:

用戶-用戶組Auth_UserUserGroup關系表可以存儲為:

UserId UserGroupId
1101 2
1101 3

新增角色:開發(fā)

RoleId RoleName
6 開發(fā)

Auth_RolePermission新增記錄:

RoleId Permission
6 9

Auth_UserGroupRole關系表可以存儲為:

UserGroupId RoleId
2 6
3 6

這樣,我們就滿足了本節(jié)提出的需求。
另外要注意到的是用戶組的ParentId字段,不要輕視這個簡單的樹狀設計,實際應用中根據(jù)業(yè)務場景會有各種不同的問題,譬如不良的SQL導致DB層面做了遞歸查詢、上級部門權(quán)限與下級部門權(quán)限的繼承關系,但這本質(zhì)屬于業(yè)務需求,不再贅述

4. RBAC權(quán)限模型

現(xiàn)在,系統(tǒng)經(jīng)過3次升級,已經(jīng)有了較為完備的權(quán)限體系,我們解決了大部分問題。
但是我們也注意到,所有的有關于權(quán)限的定義僅僅圍繞著增刪改查這一類權(quán)限控制。假如系統(tǒng)現(xiàn)在需要多控制一部分權(quán)限內(nèi)容,我們就有些捉襟見肘了。

簡單來說,我們的權(quán)限模型設計對于擴展支持不夠

譬如,業(yè)務系統(tǒng)初期對系統(tǒng)的菜單可見性有權(quán)限控制,隨著系統(tǒng)迭代,可能出現(xiàn)對文件的可操作性也需要有權(quán)限控制,這是很正常的事,顯然,依照我們的設計,系統(tǒng)無法滿足。

回顧1、2、3節(jié)的升級內(nèi)容,我們的問題其實是由單一權(quán)限元素變更為多元權(quán)限元素,如果我們能重新將被控制元素變更為單一元素,我們之前的設計則不用變更。

為了解決這個問題,我們對各種權(quán)限元素進行抽象,譬如文件訪問權(quán)限和菜單訪問權(quán)限。抽象為如下圖內(nèi)容:

現(xiàn)在,權(quán)限的Root節(jié)點變成了Permission這個抽象,它沒有具體的意義,但他將各類權(quán)限集中在了一起,使得多種權(quán)限元素重新集中在單一Permission這個抽象元素上,再次揉入到我們的系統(tǒng)中,如下圖:

這就是權(quán)限系統(tǒng)的RBAC完成模型。

至此,借助RBAC模型,我們完成了權(quán)限模塊的理論設計,它能滿足大量權(quán)限控制場景,也是業(yè)界慣用的手段,RBAC模型是一種權(quán)限模型的總結(jié)和歸納,市面上能見到的各種權(quán)限控制,都與RBAC沾邊,也就是說,掌握RBAC,就掌握了閱讀各種系統(tǒng)權(quán)限設計的基礎,有了理論支持。

不過值得注意的是,雖然我們有了理論基礎,但實際應用中,我們還要做一些擴展內(nèi)容。

譬如說權(quán)限歷史,權(quán)限模塊屬于敏感內(nèi)容,是系統(tǒng)的中樞所在,嚴謹?shù)臋?quán)限模塊肯定是不會對操作進行Delete的,而是Fake Delete以保留歷史。上文中這樣的設計為此提供了方便,當用戶的權(quán)限發(fā)生變更時,我們只需要對關系做Fake Delete即可。當然,關系本身需具備IsFakeDeleted屬性。

下一章節(jié)將介紹dotnet core的具體實現(xiàn)。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    午夜精品久久久免费视频| 亚洲专区中文字幕在线| 国产欧美日本在线播放| 99热九九热这里只有精品| 精品人妻一区二区三区四在线| 欧美日韩国产综合在线| 五月天综合网五月天综合网| 国产传媒一区二区三区| 日韩精品少妇人妻一区二区| 日本欧美一区二区三区高清| 国产爆操白丝美女在线观看| 小草少妇视频免费看视频| 国产成人高清精品尤物| 免费在线观看欧美喷水黄片| 伊人欧美一区二区三区| 一级片黄色一区二区三区| 日韩特级黄色大片在线观看| 亚洲熟女国产熟女二区三区| 真实偷拍一区二区免费视频| 国产成人在线一区二区三区| 99视频精品免费视频| 人妻偷人精品一区二区三区不卡| 午夜精品一区二区av| 亚洲欧美天堂精品在线| 国产午夜福利片在线观看| 欧美人妻盗摄日韩偷拍| 亚洲熟女少妇精品一区二区三区| 91欧美日韩精品在线| 久久精品国产在热亚洲| 国产女高清在线看免费观看| 国产精品国三级国产专不卡| 欧美美女视频在线免费看| 成人欧美一区二区三区视频| 国产小青蛙全集免费看| 日本欧美视频在线观看免费| 国产精品色热综合在线| 国产传媒高清视频在线| 国产毛片对白精品看片| 久久99夜色精品噜噜亚洲av| 国产欧美韩日一区二区三区| 亚洲乱妇熟女爽的高潮片|