摘要:權(quán)限中心的依賴聲明聲明依賴關(guān)系檢查代碼規(guī)范聲明開發(fā)依賴命名空間檢查代碼規(guī)范,執(zhí)行單元測(cè)試。單元測(cè)試持續(xù)交付一切都如此的完美,沒有測(cè)試,又如何可以證明這件事情的完美,又如何可以保障交付的質(zhì)量。
序
權(quán)限管理是無線運(yùn)營系統(tǒng)中的核心模塊,通過訪問控制策略的配置,來約定人與資源的訪問關(guān)系。
本文著重講解如何通過PHP來構(gòu)建一個(gè)靈活、通用、安全的權(quán)限管理系統(tǒng)。
關(guān)于權(quán)限首先我們來聊聊權(quán)限。
權(quán)限系統(tǒng)一直以來是我們應(yīng)用系統(tǒng)不可缺少的一個(gè)部分,若每個(gè)應(yīng)用系統(tǒng)都重新對(duì)系統(tǒng)的權(quán)限進(jìn)行設(shè)計(jì),以滿足不同系統(tǒng)用戶的需求,將會(huì)浪費(fèi)我們不少寶貴時(shí)間,所以花時(shí)間來設(shè)計(jì)一個(gè)相對(duì)通用的權(quán)限系統(tǒng)是很有意義的。
系統(tǒng)目標(biāo):對(duì)應(yīng)用系統(tǒng)的所有對(duì)象資源和數(shù)據(jù)資源進(jìn)行權(quán)限控制,比如 應(yīng)用系統(tǒng)的功能菜單、各個(gè)界面的按鈕、數(shù)據(jù)顯示的列以及各種行級(jí)數(shù)據(jù) 進(jìn)行權(quán)限的操控。
權(quán)限模型設(shè)計(jì)初期,我們學(xué)習(xí)了Amazon的 IAM ,經(jīng)過對(duì)比分析,最終我們選用 RBAC3模型 來指導(dǎo)系統(tǒng)的設(shè)計(jì)工作。
RBAC認(rèn)為權(quán)限授權(quán)實(shí)際上是Who、What、How的問題。在RBAC模型中,who、what、how構(gòu)成了訪問權(quán)限三元組,也就是“Who對(duì)What(Which)進(jìn)行How的操作”。
Who:權(quán)限的擁用者或主體(如Principal、User、Group、Role、Actor等等)
What:權(quán)限針對(duì)的對(duì)象或資源(Resource、Class)。
How:具體的權(quán)限(Privilege,正向授權(quán)與負(fù)向授權(quán))。
Operator:操作。表明對(duì)What的How操作。也就是Privilege+Resource
Role:角色,一定數(shù)量的權(quán)限的集合。權(quán)限分配的單位與載體,目的是隔離User與Privilege的邏輯關(guān)系.
PHP架構(gòu)之道「如何用PHP構(gòu)建我們的權(quán)限中心」
接下來我們將從 編碼規(guī)范、依賴管理、數(shù)據(jù)源架構(gòu)、數(shù)據(jù)處理、單元測(cè)試 等方面來體驗(yàn)一把PHP的神奇之旅。
編碼規(guī)范好的編碼規(guī)范可以改善軟件的可讀性,可以促進(jìn)團(tuán)隊(duì)成長,可以減少Bug,可以降低維護(hù)成本,可以。。。(這么X,我們必須要推廣)
PHP社區(qū)一直百花齊放,擁有大量的函數(shù)庫、框架和組件,因而PHP代碼遵循或盡量接近同一個(gè)代碼風(fēng)格就非常重要。
框架互操作組(即PHP標(biāo)準(zhǔn)組)發(fā)布了一系列推薦風(fēng)格。
閱讀PSR-0
閱讀PSR-1
閱讀PSR-2 Coding Style Guide
閱讀PSR-4 Autoloader
權(quán)限中心的目錄結(jié)構(gòu):
-- /tuniu/rbac |-- src | |-- App //應(yīng)用建模層 | | |-- City.php | | |-- Cms.php | | |-- Menu.php | |-- App.php | |-- Auth.php | |-- Orm //ActiveRecord層 | | |-- App | | | |-- Resource | | | | |-- Map.php | | | |-- Resource.php | | | |-- User.php | | |-- App.php | | |-- Log.php | | |-- Role | | | |-- User.php | | |-- Role.php | | |-- Rule.php | | |-- User.php | |-- Orm.php | |-- Utils.php |-- tests //測(cè)試 | |-- bootstrap.php | |-- fixtures | | |-- null.yml | | |-- rbac | | | |-- app.yml | | | |-- auth.yml | | | |-- role.yml | |-- rbac | | |-- appTest.php | | |-- authTest.php | | |-- roleTest.php |-- vendor |-- composer.json |-- composer.lock |-- phpunit.xml |-- README.md
PSR-2,權(quán)限應(yīng)用資源類:
namespace TuniuRbacOrmApp; use TuniuRbacOrm; use TuniuRbacOrmApp; use TuniuRbacOrmAppResourceMap; use TuniuRbacOrmRule; use TuniuRbacOrmUser; class Resource extends Orm {}
PSR-4,命名空間的約定:
類名 | 文件路徑 |
---|---|
TuniuRbacOrmAppResource | /tuniu/rbac/src/Orm/App/Resource.php |
TuniuRbacAppCms | /tuniu/rbac/src/App/Cms.php |
Composer 是PHP中用來管理依賴(dependency)關(guān)系的工具。你可以在自己的項(xiàng)目中聲明所依賴的外部工具庫(libraries),Composer會(huì)幫你安裝這些依賴的庫文件。
權(quán)限中心的依賴聲明:
{ "name": "tuniu/rbac", "require": { //聲明依賴關(guān)系 "php": ">=5.3.0", "squizlabs/php_codesniffer": "2.*", //PHP_CodeSniffer檢查代碼規(guī)范 "php-activerecord/php-activerecord": "dev-master" //ActiveRecord }, "require-dev": { //聲明開發(fā)依賴 "phpunit/phpunit": "~4.6", "phpunit/dbunit": ">=1.2" }, "autoload": { "psr-4": { "TuniuRbac": "src/" //命名空間 } } }
檢查代碼規(guī)范,執(zhí)行單元測(cè)試。
$./vendor/bin/phpcs --config-set default_standard PSR2 $./vendor/bin/phpcs src $./vendor/bin/phunit
^^^^^^ 眼澀,眼酸,眼疲勞,怎么辦。。。
騷年,如果舒服了,就使勁往下滑動(dòng)吧。。。
數(shù)據(jù)源架構(gòu)爭(zhēng)渡,爭(zhēng)渡,驚起一灘鷗鷺。
基于權(quán)限中心各表的關(guān)系(各種關(guān)聯(lián),各種回調(diào)),采用傳統(tǒng)的模式,必將把精力耗在無盡的循環(huán)中。
于是乎,開始尋覓一種數(shù)據(jù)源的架構(gòu)模式,Active Record很靠譜的出現(xiàn)了。
Active Record(中文名:活動(dòng)記錄)是一種領(lǐng)域模型模式,特點(diǎn)是一個(gè)模型類對(duì)應(yīng)關(guān)系型數(shù)據(jù)庫中的一個(gè)表,而模型類的一個(gè)實(shí)例對(duì)應(yīng)表中的一行記錄。
PHP ActiveRecord 是一個(gè)基于ActiveRecord設(shè)計(jì)模式開發(fā)的開源PHP/ORM庫。它旨在大大簡化與數(shù)據(jù)庫的交互和減少手寫SQL語句。它不同于其他的ORM,你不需要使用任何的代碼生成器,也不費(fèi)勁去手寫、維護(hù)模型層的表映射文件。這個(gè)庫的靈感來自Ruby on Rails,因此它也借鑒Ruby on Rails的想法和實(shí)現(xiàn)。(誰用誰知道)
下面介紹下這個(gè)小伙伴給編程帶來的快樂:
Validation(數(shù)據(jù)驗(yàn)證)
validates_presence_of
validates_inclusion_of
場(chǎng)景(角色表數(shù)據(jù)約定)
/** * 1:約定角色類型的范圍 * 2:約定角色狀態(tài)的范圍 */ public static $validates_inclusion_of = array( array("f_type", "in" => array("role", "group", "department", "member")), array("f_status", "in" => array(1,2)) ); /** * 設(shè)定角色名稱、角色狀態(tài)、角色類型、角色描述不能為空 */ public static $validates_presence_of = array( array("f_name"), array("f_status"), array("f_type"), array("f_desc") ); //錄入數(shù)據(jù)不滿足約定條件,就無法保存,再也不用擔(dān)心那些臟臟的數(shù)據(jù)。
Callback(回調(diào))
before_save
before_create
before_update
before_destroy
after_save
after_create
after_update
after_destroy
場(chǎng)景1(角色表操作記錄)
//定義回調(diào)函數(shù) public static $before_save = array("setMisc"); //每當(dāng)角色表保存之前,都默默的把數(shù)據(jù)格式好,好開心。。。 public function setMisc() { //創(chuàng)建時(shí)間,創(chuàng)建人 $this->is_new_record() && ($this->f_create_at = date("Y-m-d H:i:s")); $this->is_new_record() && ($this->f_create_by = $this->op); //更新時(shí)間,更新人 $this->f_update_by = $this->op; //操作人 $this->f_update_at = date("Y-m-d H:i:s"); //操作時(shí)間 }
場(chǎng)景2(新增資源,推送資源映射表):
//定義回調(diào)函數(shù) public static $after_save = array("syncRelations"); //每當(dāng)資源保存之后,自動(dòng)把資源數(shù)據(jù)中的映射字段值,推送給資源映射表。 public function syncRelations() { //獲取資源的映射字段 $mapFiledValue = $this->getMapFiledValue(); $mapFiledValue ? $this->addMap($mapFiledValue) : Map::removeAllByResourceId($this->id); }
場(chǎng)景3(角色刪除):
//定義回調(diào)函數(shù) public static $after_destroy = array("deleteRelations"); //每當(dāng)角色刪除時(shí),自動(dòng)把系統(tǒng)中角色的成員和角色的資源規(guī)則清空,而且是事務(wù)的。 public function deleteRelations() { UserRelations::removeAllByRoleId($this->id); RuleRelatinos::removeAllByRoleId($this->id); }
Association(關(guān)聯(lián))
has_many
場(chǎng)景(新增角色用戶)
//定義角色表和角色用戶表的關(guān)系 public static $has_many = array( array( "relations", "foreign_key" => "f_role_id", "class_name" => "TuniuRbacOrmRoleUser", ) ); //新增角色用戶,默默的把role_id傳遞給了角色用戶表,此處如果用SQL,簡直不忍直視。 Role::first()->create_relation( array( "f_user_id" => $uid ) );
事務(wù)(一致性與安全性)
權(quán)限系統(tǒng)中數(shù)據(jù)一致性和數(shù)據(jù)安全性的重要性是不言而喻,不用事務(wù)會(huì)被BS的。
在此我們鄭重承諾,權(quán)限系統(tǒng)中每一次數(shù)據(jù)增刪改請(qǐng)求,都是事務(wù)處理的。
比如角色保存:
self::transaction( function () use ($params, &$role) { $role->f_name = $params["name"]; $role->f_status = $params["status"]; $role->f_type = $params["type"]; $role->f_desc = $params["desc"]; if ($role->is_invalid()) { throw new Exception("角色相關(guān)操作失敗", "900202"); } $role->save(); } );
篇幅有限,這個(gè)小伙伴的戰(zhàn)斗力場(chǎng)景遠(yuǎn)甚于此。
單元測(cè)試(持續(xù)交付)坦白的說,用AR是一種編程享受。
一切都如此的完美,沒有測(cè)試,又如何可以證明這件事情的完美,又如何可以保障交付的質(zhì)量。
PHPUnit 是一個(gè)輕量級(jí)的PHP測(cè)試框架。它是在PHP5下面對(duì)JUnit3系列版本的完整移植,是xUnit測(cè)試框架家族的一員(它們都基于模式先鋒Kent Beck的設(shè)計(jì))。
單元測(cè)試是一種提高軟件質(zhì)量非常有效的方法,但很重要的是我們要去實(shí)踐和體會(huì)。
簡單的介紹下權(quán)限管理中的角色行為測(cè)試用例:
角色行為測(cè)試
數(shù)據(jù)集(YAML)
t_rbac_user: - f_id: 1 f_name: "zhaoyang2" f_create_at: "2013-10-10 17:04:05" t_rbac_role_user: - f_id: 1 f_user_id: 1 f_role_id: 1 t_rbac_role: - f_id: 1 f_name: "運(yùn)營研發(fā)部-1" f_status: 1, f_type: "department" f_desc: "我們是運(yùn)營研發(fā)部-1" f_create_at: "2013-10-10 17:04:05" f_create_by: "zhaoyang2" f_update_by: "zhaoyang2"
測(cè)試代碼:
//預(yù)設(shè)數(shù)據(jù)集 public function getDataSet() { return new PHPUnit_Extensions_Database_DataSet_YamlDataSet( fixture("rbac/role.yml") ); } /** * 權(quán)限操作-異常驗(yàn)證 * @expectedException Exception * @expectedExceptionMessage 您無權(quán)運(yùn)營當(dāng)前數(shù)據(jù) */ public function testRoleDeleteException() { Role::first()->remove(); } /** * 權(quán)限操作-刪除驗(yàn)證 */ public function testRoleDelete() { Role::first()->remove("zhaoyang2"); //驗(yàn)證數(shù)據(jù)行 $this->assertEquals(1, $this->getConnection()->getRowCount(Role::$table_name)); $this->assertEquals(1, $this->getConnection()->getRowCount(UserRelation::$table_name)); }
鑒權(quán)用例和應(yīng)用管理用例,遠(yuǎn)比這個(gè)復(fù)雜,感興趣的同學(xué)可以去 Fork 一把,了解下PHPUNIT的魅力。
結(jié)束語PHPUNIT很強(qiáng)大,想合理運(yùn)用的話,沒有任何捷徑,開始寫測(cè)試用例吧。。
其實(shí)說架構(gòu)算上下,就是和大家分享下權(quán)限中心的PHP之道。
高效便捷的使用PHP服務(wù)我們的工作。
多交流,多分享,書寫更好的PHP代碼,享受編程和技術(shù)所帶來的快樂。
RBAC
PHP之道
深入理解PHP內(nèi)核
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/21552.html
摘要:認(rèn)為權(quán)限授權(quán)實(shí)際上是的問題。具體的權(quán)限,正向授權(quán)與負(fù)向授權(quán)。應(yīng)用建模業(yè)務(wù)場(chǎng)景權(quán)限管理鑒權(quán)設(shè)計(jì)應(yīng)用建模系統(tǒng)架構(gòu)上支撐權(quán)限系統(tǒng)靈活配置,不僵硬字段,不僵硬行為,基于各種業(yè)務(wù)權(quán)限管控的特征靈活設(shè)計(jì)。表示許可權(quán)與角色之間多對(duì)多的指派關(guān)系。 序 之前寫過一篇大話權(quán)限中心的PHP架構(gòu)之道,主要是從軟件工程角度介紹,如何通過編碼規(guī)范、依賴管理、數(shù)據(jù)源架構(gòu)、事務(wù)處理、單元測(cè)試等技術(shù),來保障權(quán)限系統(tǒng)的高...
摘要:認(rèn)為權(quán)限授權(quán)實(shí)際上是的問題。具體的權(quán)限,正向授權(quán)與負(fù)向授權(quán)。應(yīng)用建模業(yè)務(wù)場(chǎng)景權(quán)限管理鑒權(quán)設(shè)計(jì)應(yīng)用建模系統(tǒng)架構(gòu)上支撐權(quán)限系統(tǒng)靈活配置,不僵硬字段,不僵硬行為,基于各種業(yè)務(wù)權(quán)限管控的特征靈活設(shè)計(jì)。表示許可權(quán)與角色之間多對(duì)多的指派關(guān)系。 序 之前寫過一篇大話權(quán)限中心的PHP架構(gòu)之道,主要是從軟件工程角度介紹,如何通過編碼規(guī)范、依賴管理、數(shù)據(jù)源架構(gòu)、事務(wù)處理、單元測(cè)試等技術(shù),來保障權(quán)限系統(tǒng)的高...
摘要:從年月開始,的開發(fā)由作者目前就職贊助。武器一覽無線運(yùn)營播種機(jī)模型動(dòng)態(tài)表單屬性中心標(biāo)簽系統(tǒng)權(quán)限中心模型位置管理一切皆位置回到主題,下面就為大家詳細(xì)介紹下,我們?nèi)绾瓮嫠!?chǎng)景包括頁面緩存限速器頁面性能分析狀態(tài)統(tǒng)計(jì)智能提醒異常線路。 Redis-簡介 Redis是一個(gè)開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。從2...
摘要:的本質(zhì)是團(tuán)隊(duì)博客,關(guān)注互聯(lián)網(wǎng)創(chuàng)業(yè)技術(shù),每周推薦篇優(yōu)質(zhì)文章。堅(jiān)持爭(zhēng)取做到每周更新,與讀者一起進(jìn)步。第十一期第十期第九期第八期第七期第六期第五期第四期第三期切換至,第二期發(fā)布。創(chuàng)刊,用發(fā)布了第一次。 Tuniu Weekly Inspired By 《灣區(qū)日?qǐng)?bào)》 我們團(tuán)隊(duì)也想基于這種模式,讓大家感受到技術(shù)的人文。 《Tuniu Weekly》就這樣產(chǎn)生了。 《Tuniu Weekly》...
閱讀 2239·2021-11-22 09:34
閱讀 1349·2021-10-11 10:59
閱讀 4449·2021-09-22 15:56
閱讀 3311·2021-09-22 15:08
閱讀 3415·2019-08-30 14:01
閱讀 787·2019-08-30 11:16
閱讀 1139·2019-08-26 13:51
閱讀 2920·2019-08-26 13:43