日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

设计一个权限系统-RBAC

發布時間:2024/3/13 windows 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计一个权限系统-RBAC 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

系統安全一直是在系統開發中不可規避的問題,而權限控制又跟系統安全密不可分,大到用戶的訪問,小到一個頁面的按鈕,都有可能涉及到權限的控制。

RBAC權限模型

迄今為止最為普及的權限設計模型是RBAC模型,基于角色的訪問控制(Role-Based Access Control)。

1、RBAC0模型

簡單地說,一個用戶擁有若干角色,每一個角色擁有若干權限。這樣,就構造成“用戶-角色-權限”的授權模型。

RBAC0模型如下:

這是權限最基礎也是最核心的模型,它包括用戶/角色/權限,其中用戶和角色是多對多的關系,角色和權限也是多對多的關系。

用戶是發起操作的主體,按類型分可分為2B和2C用戶,可以是后臺管理系統的用戶,可以是OA系統的內部員工,也可以是面向C端的用戶,比如阿里云的用戶。

角色起到了橋梁的作用,連接了用戶和權限的關系,每個角色可以關聯多個權限,同時一個用戶關聯多個角色,那么這個用戶就有了多個角色的多個權限。有人會問了為什么用戶不直接關聯權限呢?

在用戶基數小的系統,比如20個人的小系統,管理員可以直接把用戶和權限關聯,工作量并不大,選擇一個用戶勾選下需要的權限就完事了。

但是在實際企業系統中,用戶基數比較大,其中很多人的權限都是一樣的,就是個普通訪問權限,如果管理員給100人甚至更多授權,工作量巨大。

這就引入了"角色(Role)"概念,一個角色可以與多個用戶關聯,管理員只需要把該角色賦予用戶,那么用戶就有了該角色下的所有權限,這樣設計既提升了效率,也有很大的拓展性。

一句話概括就是:權限系統維護的是人和可進行行為的關聯關系。

那么系統的每個用戶可以看做是一堆可以進行的行為的集合。

這句話有點不好理解的話,你就按照用戶畫像那么理解,在權限系統里,每個用戶身上打滿了一堆可以進行行為的標簽。

權限是用戶可以訪問的資源,包括頁面權限操作權限數據權限

頁面權限:即用戶登錄系統可以看到的頁面,由菜單來控制,菜單包括一級菜單和二級菜單,只要用戶有一級和二級菜單的權限,那么用戶就可以訪問頁面

操作權限: 即頁面的功能按鈕,包括查看、新增、修改、刪除、審核等,用戶點擊刪除按鈕時,后臺會校驗用戶角色下的所有權限是否包含該刪除權限,如果是,就可以進行下一步操作,反之提示無權限。有的系統要求"可見即可操作",意思是如果頁面上能夠看到操作按鈕,那么用戶就可以操作,要實現此需求,這里就需要前端來配合,前端開發把用戶的權限信息緩存,在頁面判斷用戶是否包含此權限,如果有,就顯示該按鈕,如果沒有,就隱藏該按鈕。某種程度上提升了用戶體驗,但是在實際場景可自行選擇是否需要這樣做。

數據權限:數據權限就是用戶在同一頁面看到的數據是不同的,比如財務部只能看到其部門下的用戶數據,采購部只看采購部的數據,在一些大型的公司,全國有很多城市和分公司,比如杭州用戶登錄系統只能看到杭州的數據,上海用戶只能看到上海的數據,解決方案一般是把數據和具體的組織架構關聯起來,舉個例子,再給用戶授權的時候,用戶選擇某個角色同時綁定組織如財務部或者合肥分公司,那么該用戶就有了該角色下財務部或合肥分公司下的的數據權限。

以上是RBAC的核心設計及模型分析,此模型也叫做RBAC0,而基于核心概念之上,RBAC還提供了擴展模式:包括RBAC1、RBAC2、RBAC3模型。

下面介紹這三種類型

2、RBAC1模型

此模型引入了角色繼承(Hierarchical Role)概念,即角色具有上下級的關系,角色間的繼承關系可分為一般繼承關系和受限繼承關系。

一般繼承關系僅要求角色繼承關系是一個絕對偏序關系,允許角色間的多繼承。而受限繼承關系則進一步要求角色繼承關系是一個樹結構,實現角色間的單繼承。這種設計可以給角色分組和分層,一定程度簡化了權限管理工作。

3、 RBAC2模型

基于核心模型的基礎上,進行了角色的約束控制,RBAC2模型中添加了責任分離關系,其規定了權限被賦予角色時,或角色被賦予用戶時,以及當用戶在某一時刻激活一個角色時所應遵循的強制性規則。責任分離包括靜態責任分離和動態責任分離。

主要包括以下約束:

互斥角色:同一用戶只能分配到一組互斥角色集合中至多一個角色,支持責任分離的原則。互斥角色是指各自權限互相制約的兩個角色。比如財務部有會計和審核員兩個角色,他們是互斥角色,那么用戶不能同時擁有這兩個角色,體現了職責分離原則。

基數約束:一個角色被分配的用戶數量受限;一個用戶可擁有的角色數目受限;同樣一個角色對應的訪問權限數目也應受限,以控制高級權限在系統中的分配

先決條件角色: 即用戶想獲得某上級角色,必須先獲得其下一級的角色。

4、RBAC3模型

即最全面的權限管理,它是基于RBAC0,將RBAC1和RBAC2進行了整合

5、用戶組

當平臺用戶基數增大,角色類型增多時,而且有一部分人具有相同的屬性,比如財務部的所有員工,如果直接給用戶分配角色,管理員的工作量就會很大,如果把相同屬性的用戶歸類到某用戶組,那么管理員直接給用戶組分配角色,用戶組里的每個用戶即可擁有該角色,以后其他用戶加入用戶組后,即可自動獲取用戶組的所有角色,退出用戶組,同時也撤銷了用戶組下的角色,無須管理員手動管理角色。

根據用戶組是否有上下級關系,可以分為有上下級的用戶組和普通用戶組。

具有上下級關系的用戶組:最典型的例子就是部門和職位,可能多數人沒有把部門職位和用戶組關聯起來吧。當然用戶組是可以拓展的,部門和職位常用于內部的管理系統,如果是面向C端的系統,比如淘寶網的商家,商家自身也有一套組織架構,比如采購部,銷售部,客服部,后勤部等,有些人擁有客服權限,有些人擁有上架權限等等,所以用戶組是可以拓展的。

普通用戶組:即沒有上下級關系,和組織架構,職位都沒有關系,也就是說可以跨部門,跨職位,舉個例子,某電商后臺管理系統,有拼團活動管理角色,我們可以設置一個拼團用戶組,該組可以包括研發部的后臺開發人員,運營部的運營人員,采購部的人員等等。

每個公司都會涉及到到組織和職位,下面就重點介紹這兩個。

5.1 組織

常見的組織架構如下圖:

我們可以把組織與角色進行關聯,用戶加入組織后,就會自動獲得該組織的全部角色,無須管理員手動授予,大大減少工作量,同時用戶在調崗時,只需調整組織,角色即可批量調整。

組織的另外一個作用是控制數據權限,把角色關聯到組織,那么該角色只能看到該組織下的數據權限。

5.2 職位

假設財務部的職位如下圖:

每個組織部門下都會有多個職位,比如財務部有總監,會計,出納等職位,雖然都在同一部門,但是每個職位的權限是不同的,職位高的擁有更多的權限。總監擁有所有權限,會計和出納擁有部分權限。特殊情況下,一個人可能身兼多職。

6、含有組織/職位/用戶組的模型

根據以上場景,新的權限模型就可以設計出來了,如下圖:

根據系統的復雜度不同,其中的多對多關系和一對一關系可能會有變化。

在單系統且用戶類型單一的情況下,用戶和組織是一對一關系,組織和職位是一對多關系,用戶和職位是一對一關系,組織和角色是一對一關系,職位和角色是一對一關系,用戶和用戶組是多對對關系,用戶組和角色是一對一關系,當然這些關系也可以根據具體業務進行調整。模型設計并不是死的,如果小系統不需要用戶組,這塊是可以去掉的。

分布式系統且用戶類型單一的情況下,到這里權限系統就會變得很復雜,這里就要引入了一個"系統"概念,此時系統架構是個分布式系統,權限系統獨立出來,負責所有的系統的權限控制,其他業務系統比如商品中心,訂單中心,用戶中心,每個系統都有自己的角色和權限,那么權限系統就可以配置其他系統的角色和權限。

# 授權流程

授權即給用戶授予角色,按流程可分為手動授權和審批授權。權限中心可同時配置這兩種,可提高授權的靈活性。

手動授權:管理員登錄權限中心為用戶授權,根據在哪個頁面授權分為兩種方式:給用戶添加角色,給角色添加用戶。

給用戶添加角色就是在用戶管理頁面,點擊某個用戶去授予角色,可以一次為用戶添加多個角色;給角色添加用戶就是在角色管理頁面,點擊某個角色,選擇多個用戶,實現了給批量用戶授予角色的目的。

審批授權:即用戶申請某個職位角色,那么用戶通過OA流程申請該角色,然后由上級審批,該用戶即可擁有該角色,不需要系統管理員手動授予。

# 表結構

有了上述的權限模型,設計表結構就不難了,下面是多系統下的表結構,簡單設計下,主要提供思路。

# 權限框架

RBAC模型5大屬性,分別是:
1 用戶屬性(張三、李四、王五)
2 角色屬性(銷售經理、銷售、前臺)
3 用戶與角色的關系(張三 是 銷售經理 、李四 王五 是 銷售)
4 權限(添加客戶、編輯客戶、刪除客戶,查看客戶)
5 權限與角色的關系(銷售 擁有 查看客戶的 權 限、銷售經理可以 查看/添加/刪除/編輯客戶的)

一個RBAC權限模塊,必然要實現三個功能
用戶管理
用戶列表
添加用戶
編輯用戶
設置用戶角色
角色管理 角色列表
添加角色
編輯角色
設置角色權限
權限管理
權限列表
新增權限
編輯權限

數據表設計

用戶表

?

CREATE TABLE `user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名',`email` varchar(30) NOT NULL DEFAULT '' COMMENT '郵箱',`is_admin` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否是超級管理員 1表示是 0 表示不是',`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態 1:有效 0:無效',`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新時間',`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間',PRIMARY KEY (`id`),KEY `idx_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';

角色表

?

CREATE TABLE `role` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL DEFAULT '' COMMENT '角色名稱',`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態 1:有效 0:無效',`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新時間',`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';

用戶角色表

?

CREATE TABLE `user_role` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`uid` int(11) NOT NULL DEFAULT '0' COMMENT '用戶id',`role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色ID',`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間',PRIMARY KEY (`id`),KEY `idx_uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶角色表';

權限詳情表

?

CREATE TABLE `access` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`title` varchar(50) NOT NULL DEFAULT '' COMMENT '權限名稱',`urls` varchar(1000) NOT NULL DEFAULT '' COMMENT 'json 數組',`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態 1:有效 0:無效',`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新時間',`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='權限詳情表';

角色權限表

?

CREATE TABLE `role_access` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色id',`access_id` int(11) NOT NULL DEFAULT '0' COMMENT '權限id',`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間',PRIMARY KEY (`id`),KEY `idx_role_id` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色權限表';

用戶操作記錄表

?

CREATE TABLE `app_access_log` (`id` int(11) NOT NULL AUTO_INCREMENT,`uid` bigint(20) NOT NULL DEFAULT '0' COMMENT '品牌UID',`target_url` varchar(255) NOT NULL DEFAULT '' COMMENT '訪問的url',`query_params` longtext NOT NULL COMMENT 'get和post參數',`ua` varchar(255) NOT NULL DEFAULT '' COMMENT '訪問ua',`ip` varchar(32) NOT NULL DEFAULT '' COMMENT '訪問ip',`note` varchar(1000) NOT NULL DEFAULT '' COMMENT 'json格式備注字段',`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`),KEY `idx_uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶操作記錄表';

代碼實現
本系統所有頁面都是需要登錄之后才能訪問的, 在框架中加入統一驗證方法

?

public function beforeAction($action) {$login_status = $this->checkLoginStatus();if ( !$login_status && !in_array( $action->uniqueId,$this->allowAllAction ) ) {if(Yii::$app->request->isAjax){$this->renderJSON([],"未登錄,請返回用戶中心",-302);}else{$this->redirect( UrlService::buildUrl("/user/login") );//返回到登錄頁面}return false;}//保存所有的訪問到數據庫當中$get_params = $this->get( null );$post_params = $this->post( null );$model_log = new AppAccessLog();$model_log->uid = $this->current_user?$this->current_user['id']:0;$model_log->target_url = isset( $_SERVER['REQUEST_URI'] )?$_SERVER['REQUEST_URI']:'';$model_log->query_params = json_encode( array_merge( $post_params,$get_params ) );$model_log->ua = isset( $_SERVER['HTTP_USER_AGENT'] )?$_SERVER['HTTP_USER_AGENT']:'';$model_log->ip = isset( $_SERVER['REMOTE_ADDR'] )?$_SERVER['REMOTE_ADDR']:'';$model_log->created_time = date("Y-m-d H:i:s");$model_log->save( 0 );/*** 判斷權限的邏輯是* 取出當前登錄用戶的所屬角色,* 在通過角色 取出 所屬 權限關系* 在權限表中取出所有的權限鏈接* 判斷當前訪問的鏈接 是否在 所擁有的權限列表中*///判斷當前訪問的鏈接 是否在 所擁有的權限列表中if( !$this->checkPrivilege( $action->getUniqueId() ) ){$this->redirect( UrlService::buildUrl( "/error/forbidden" ) );return false;}return true; }

檢查是否有訪問指定鏈接的權限

?

public function checkPrivilege( $url ){//如果是超級管理員 也不需要權限判斷if( $this->current_user && $this->current_user['is_admin'] ){return true;}//有一些頁面是不需要進行權限判斷的if( in_array( $url,$this->ignore_url ) ){return true;}return in_array( $url, $this->getRolePrivilege( ) ); }

獲取某用戶的所有權限,取出指定用戶的所屬角色, 在通過角色取出所屬權限關系,在權限表中取出所有的權限鏈接

?

public function getRolePrivilege($uid = 0){if( !$uid && $this->current_user ){$uid = $this->current_user->id;}if( !$this->privilege_urls ){$role_ids = UserRole::find()->where([ 'uid' => $uid ])->select('role_id')->asArray()->column();if( $role_ids ){//在通過角色 取出 所屬 權限關系$access_ids = RoleAccess::find()->where([ 'role_id' => $role_ids ])->select('access_id')->asArray()->column();//在權限表中取出所有的權限鏈接$list = Access::find()->where([ 'id' => $access_ids ])->all();if( $list ){foreach( $list as $_item ){$tmp_urls = @json_decode( $_item['urls'],true );$this->privilege_urls = array_merge( $this->privilege_urls,$tmp_urls );}}}}return $this->privilege_urls ; }

# 結語

權限系統可以說是整個系統中最基礎,同時也可以很復雜的,在實際項目中,會遇到多個系統,多個用戶類型,多個使用場景,這就需要具體問題具體分析,但最核心的RBAC模型是不變的,我們可以在其基礎上進行擴展來滿足需求。

?

總結

以上是生活随笔為你收集整理的设计一个权限系统-RBAC的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。