摘要:原文來自上一篇文章講了用戶的注冊(cè),驗(yàn)證和登錄,這一篇文章按照約定來說說之中的用戶和權(quán)限控制。探尋上面的一些列設(shè)置和代碼更改,已經(jīng)實(shí)現(xiàn)了一小部分的用戶控制登錄的用戶才能發(fā)表。
原文來自: https://jellybool.com/post/programming-with-yii2-user-access-controls
上一篇文章講了用戶的注冊(cè),驗(yàn)證和登錄,這一篇文章按照約定來說說Yii2之中的用戶和權(quán)限控制。
你可以直接到Github下載源碼,以便可以跟上進(jìn)度,你也可以重頭開始,一步一步按照這個(gè)教程來做。
鑒于本教材基于Yii2 Basic,所以對(duì)RBAC的詳細(xì)講解我后面再多帶帶出文章來說說吧,這里主要是簡(jiǎn)單地說一說權(quán)限控制
上一篇文章所實(shí)現(xiàn)的功能還比較簡(jiǎn)單,可以發(fā)一條狀態(tài),但是不知道你注意到?jīng)]有,如果是沒有注冊(cè)的用戶也可以使用我們的應(yīng)用(類似小微博)來發(fā)狀態(tài),這是不符合情理的。正確的做法是在用戶沒有注冊(cè),登錄之前,我們甚至都不應(yīng)該給沒有注冊(cè)的用戶看到我們創(chuàng)建狀態(tài)的頁面,即是http://localhost:8999/status/create就不應(yīng)該讓游客看到,更不用說編輯和刪除一條狀態(tài)(status)了。
權(quán)限控制什么是權(quán)限控制?個(gè)人覺得在一個(gè)Web應(yīng)用當(dāng)中,有以下幾種常見的角色和權(quán)限控制:
1. 游客,也就是沒有注冊(cè)的用戶,一般這個(gè)權(quán)限是最小的,對(duì)于一些需要登錄訪問的頁面沒有訪問權(quán)限 2. 用戶,這里的用戶特指注冊(cè)用戶,注冊(cè)過后的用戶一般可以使用整個(gè)web應(yīng)用的主要功能,比如我們這里的發(fā)表一條狀態(tài)(status) 3. 作者,這個(gè)不知道確切應(yīng)該使用什么名詞來描述,作者是在用戶注冊(cè)之后的一個(gè)權(quán)限判斷,比如A發(fā)表的status狀態(tài),B君不能進(jìn)行編輯,刪除等,反之亦然。 4. 管理員,這里的管理員通常會(huì)是應(yīng)用的開發(fā)者(所有者,或者應(yīng)該這么說),幾乎可以說是對(duì)站點(diǎn)的所有權(quán)限都有
Yii2自帶的權(quán)限控制默認(rèn)只支持兩個(gè)角色:
guest(游客,沒有登錄的,用?表示)
authenticated (登錄了的,用@表示)
在這里我們需要實(shí)現(xiàn)的是對(duì)這兩種不同的角色指定不同的訪問權(quán)限,就是為他們分配不同的可以訪問的控制器或者方法。
目前我們?nèi)绻苯狱c(diǎn)擊導(dǎo)航欄的Status,我們還是可以在沒有登錄的情況之下進(jìn)行發(fā)表狀態(tài)(status),所以我們需要改一下我們的代碼和邏輯,Yii2在這方面的控制做得非常好,其實(shí)實(shí)現(xiàn)這個(gè)我們只需要修改一下StatusController.php里面的behaviors()方法而已,在這里面加入一段access設(shè)置:
``` public function behaviors() { return [ "verbs" => [ "class" => VerbFilter::className(), "actions" => [ "delete" => ["post"], ], ], "access" => [ "class" => AccessControl::className(), "only" => ["index","create","update","view"], "rules" => [ // allow authenticated users [ "allow" => true, "roles" => ["@"], ], // everything else is denied ], ], ]; } ```
加上access這一段之后,我們?cè)俅吸c(diǎn)擊Status,Yii2就會(huì)將未登錄的我重定向到登錄頁面。
而且,這個(gè)時(shí)候,一旦你登入進(jìn)去,Yii會(huì)默認(rèn)自動(dòng)跳轉(zhuǎn)到上一個(gè)url,也就是我們剛剛點(diǎn)擊的status/index。
添加映射關(guān)系用戶一旦登錄進(jìn)來之后,我們就可以通過下面這行代碼來獲取用戶的id了:
``` Yii::$app->user->getId(); ```
一旦用戶的id獲取到,我們可以做的事就很多了。這里我們先來將一條狀態(tài)和用戶聯(lián)系起來,也就是添加用戶與說說的映射關(guān)系。要實(shí)現(xiàn)這個(gè)目標(biāo)我們需要先修改我們的數(shù)據(jù)表(體驗(yàn)一下當(dāng)初設(shè)計(jì)數(shù)據(jù)表考慮不周全的情況):
``` ./yii migrate/create extend_status_table_for_created_by Yii Migration Tool (based on Yii v2.0.6) Create new migration "/Users/jellybool/Desktop/helloYii/migrations/m150806_034325_extend_status_table_for_created_by.php"? (yes|no) [no]:yes New migration created successfully. ```
打開對(duì)應(yīng)的migration文件,編輯up()和down()方法,如果你想加入數(shù)據(jù)庫的事務(wù)管理功能,你可以使用safeUp()和safeDown()方法
``` public function up() { $this->addColumn("{{%status}}","created_by",Schema::TYPE_INTEGER." NOT NULL"); $this->addForeignKey("fk_status_created_by", "{{%status}}", "created_by", "{{%user}}", "id", "CASCADE", "CASCADE"); } public function down() { $this->dropForeignKey("fk_status_created_by","{{%status}}"); $this->dropColumn("{{%status}}","created_by"); } ```
我們需要為status表添加一個(gè)created_by字段,并且將它跟user表的id設(shè)為外鍵關(guān)系。
如果你在status表里面有一條數(shù)據(jù)記錄,你需要先刪除這一條記錄,不然可能會(huì)報(bào)錯(cuò)。
執(zhí)行migrate/up:
``` ./yii migrate/up Yii Migration Tool (based on Yii v2.0.6) Total 1 new migration to be applied: m150806_034325_extend_status_table_for_created_by Apply the above migration? (yes|no) [no]:yes *** applying m150806_034325_extend_status_table_for_created_by > add column created_by integer NOT NULL to table {{%status}} ... done (time: 0.032s) > add foreign key fk_status_created_by: {{%status}} (created_by) references {{%user}} (id) ... done (time: 0.014s) *** applied m150806_034325_extend_status_table_for_created_by (time: 0.059s) ```
數(shù)據(jù)表的外鍵設(shè)置好之后,我們就可以來聲明Status和User的關(guān)系了,不過在開始之前需要修改一下User.php里面的內(nèi)容:
```直接將原來的User模型的代碼都刪掉,只需要我們上面的代碼就可以了,因?yàn)槲覀兪褂昧薡ii2-User,
這里就是使用dektriumusermodelsUser這個(gè)模型,然后修改一下我們的config/web.php,再我們之前的user中加入幾行代碼:``` "modules" => [ "user" => [ "class" => "dektriumuserModule", "confirmWithin" => 21600, // add the following 3 lines "modelMap" => [ "User" => "appmodelsUser", ], "cost" => 12, "admins" => ["admin"] ], ], ```這樣之后,我們的User和Status的對(duì)應(yīng)關(guān)系就會(huì)建立起來。
然后我們?cè)赟tatus.php寫上以下的說明:
``` public function getUser() { return $this->hasOne(User::className(), ["id" => "created_by"]); } ```這里聲明的映射關(guān)系為hasOne,也就是說,一條狀態(tài)status(說說)對(duì)應(yīng)一個(gè)用戶(User),我們通過["id" => "created_by"]來指定外鍵映射。
有了Status和User的對(duì)應(yīng)關(guān)系之后,我們需要在用戶發(fā)表狀態(tài)的時(shí)候?qū)⒂脩舻膇d保存到Status的created_by這一個(gè)字段中,所以我們需要在StatusController中的actionCreate方法中加上一行代碼:
``` if ($model->load(Yii::$app->request->post())) { $model->created_by = Yii::$app->user->getId();//add this line $model->created_at = time(); $model->updated_at = time(); if ($model->save()) { return $this->redirect(["view", "id" => $model->id]); } } ```這里需要確認(rèn)的是,你需要保證create方法只能是登錄進(jìn)來的用戶才能訪問觸發(fā)。
為了更好地展示一條狀態(tài)stutas的信息,我們修改一下展示狀態(tài)的視圖文件:status/view.php :
``` = DetailView::widget([ "model" => $model, "attributes" => [ "id", "user.email", // add this line "message:ntext", "created_by", // add this line "permissions", "created_at", "updated_at", ], ]) ?> ```上面的user.email中的user其實(shí)是觸發(fā)Status::getUser()這個(gè)方法。
這樣一刷新之后,我們就可以看到創(chuàng)建這條狀態(tài)的用戶id和email了。
探尋RBAC上面的一些列設(shè)置和代碼更改,已經(jīng)實(shí)現(xiàn)了一小部分的用戶控制:登錄的用戶才能發(fā)表status。然而這還不能滿足我們?cè)谌粘J褂玫男枨螅热缥覀儸F(xiàn)在怎么確定一個(gè)用戶能不能對(duì)某條狀態(tài)進(jìn)行修改和刪除?或者說,管理員的角色在哪里體現(xiàn)呢?現(xiàn)在貌似都是平等的角色,相同的權(quán)限,對(duì)于登錄的用戶來說。
鑒于官方文檔或者很多關(guān)于Yii2 RBAC的資料都是基于Yii2 Advanced Template,而我們一開始使用的是Yii2 Basic Template,并且我們也引入Yii2-User,所以這里我們嘗試來自己實(shí)現(xiàn)一點(diǎn)點(diǎn)的用戶權(quán)限控制。
首先我們需要在User中定義一些跟角色(role)相關(guān)的規(guī)定,比如根據(jù)不同的用戶角色來賦予不同的常量:
``` class User extends BaseUser { const ROLE_USER = 10; const ROLE_MODERATOR = 20; const ROLE_ADMIN = 30; } ```上面的代碼寫在User模型里面,這里定義了三種角色,ROLE_USER,ROLE_MODERATOR,ROLE_ADMIN,USER可以發(fā)表狀態(tài),MODERATOR可以修改但是不可以刪除,ADMIN可以修改和刪除。
然后在helloYii/目錄之下創(chuàng)建一個(gè)components/目錄,里面新建一個(gè)AccessRule.php文件:
roles) === 0) { return true; } foreach ($this->roles as $role) { if ($role === "?") { if ($user->getIsGuest()) { return true; } } elseif ($role === User::ROLE_USER) { if (!$user->getIsGuest()) { return true; } // Check if the user is logged in, and the roles match } elseif (!$user->getIsGuest() && $role === $user->identity->role) { return true; } } return false; } }這里就直接借用Yii2自帶的yiifiltersAccessRule來控制權(quán)限規(guī)則。但是由于Yii2-User在創(chuàng)建user數(shù)據(jù)表的時(shí)候并沒有role這個(gè)字段,所以我們需要手動(dòng)添加,你可以直接在mysql敲命令行,或者也可以通過數(shù)據(jù)庫管理工具來添加。
最后更新一下我們的StatusController.php文件,這里的behaviors()方法會(huì)做出一些調(diào)整:
[ "class" => VerbFilter::className(), "actions" => [ "delete" => ["post"], ], ], "access" => [ "class" => AccessControl::className(), // We will override the default rule config with the new AccessRule class "ruleConfig" => [ "class" => AccessRule::className(), ], "only" => ["index","create", "update", "delete"], "rules" => [ [ "actions" => ["index","create"], "allow" => true, // Allow users, moderators and admins to create "roles" => [ User::ROLE_USER, User::ROLE_MODERATOR, User::ROLE_ADMIN ], ], [ "actions" => ["update"], "allow" => true, // Allow moderators and admins to update "roles" => [ User::ROLE_MODERATOR, User::ROLE_ADMIN ], ], [ "actions" => ["delete"], "allow" => true, // Allow admins to delete "roles" => [ User::ROLE_ADMIN ], ], ], ], ]; }我們上面根據(jù)不同等級(jí)的用戶賦予不同的訪問權(quán)限,這時(shí)候,如果你先logout出來,再登錄回去,你還是可以看到這些status,但是一旦你點(diǎn)擊
delete(刪除按鈕),你將會(huì)看到一個(gè)報(bào)錯(cuò)的頁面:我們手動(dòng)創(chuàng)建的role是成功,但是我們?cè)趺唇o一個(gè)注冊(cè)的用戶默認(rèn)的權(quán)限呢,我們這里就是想實(shí)現(xiàn)在新用戶注冊(cè)的時(shí)候賦予用戶ROLE_USER的角色和權(quán)限。由于Yii2-User是在vendordektriumyii2-usermodelsRegistrationForm.php這個(gè)文件里面進(jìn)行創(chuàng)建新的用戶的,我門這里只要修改一個(gè)小地方,找到register()方法:
public function register() { if ($this->validate()) { $user = $this->module->manager->createUser([ "email" => $this->email, "username" => $this->username, "password" => $this->password, "role"=>10, // add this line User::ROLE_USER; ]); return $user->register(); } return false; }添加"role"=>10就可以了。
如果你想證明一下我們的權(quán)限是否正確,你可以手動(dòng)修改數(shù)據(jù)庫中的role字段的數(shù)值,然后在進(jìn)行修改和刪除等操作,看看是否可以正確運(yùn)行。
權(quán)限控制其實(shí)可以說是Yii2的一大特色和亮點(diǎn),在這里可能并沒有說得很清晰,只是簡(jiǎn)單地實(shí)現(xiàn)了一些規(guī)則,有機(jī)會(huì)借助Yii2 Advanced Template來實(shí)現(xiàn)一下。
源碼會(huì)放在 Github:https://github.com/JellyBool/helloYii
下一節(jié)下一節(jié)嘗試集成一個(gè)編輯器和做一下url的美化,內(nèi)容應(yīng)該會(huì)比較簡(jiǎn)單
Happy Hacking
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/21044.html
摘要:原文來自這一篇文章的開頭就無需多言了,緊接著上一篇的內(nèi)容和計(jì)劃,這一篇我們來說說的和。,那既然這樣,我們就來實(shí)現(xiàn)一下唄。所以我們首先需要將表中的幾條數(shù)據(jù)刪掉。下一節(jié)再詳細(xì)講講吧,這一節(jié)寫下來貌似要說的實(shí)在有點(diǎn)多。 原文來自:https://jellybool.com/post/programming-with-yii2-behaviors-and-validat... 這一篇...
摘要:開始使用郵箱配置好了之后,我們就可以開始使用了,首先我們來修改一下我們的導(dǎo)航欄,因?yàn)槲覀兿雽?shí)現(xiàn)的就是我們常??吹降脑趯?dǎo)航欄的右側(cè)的注冊(cè)和登錄按鈕。 原文來自: https://jellybool.com/post/programming-with-yii2-integrating-user-regi... 本來打算昨晚寫的這篇教程,但是忙著約會(huì)去了,所以現(xiàn)在補(bǔ)上吧。 上一篇...
摘要:而這些問題目前的最好解決方案就是集成一個(gè)編輯器,鑒于大家這里不是指程序員都是喜歡所見即所得,所以,這里我主要是演示怎么集成所見即所得的富文本編輯器。 原文來自: https://jellybool.com/post/programming-with-yii2-rich-text-input-with-redactor 首先,很慚愧的是,前幾天都出去外面玩了,沒有及時(shí)更新教程,...
摘要:而且很明顯地,我們可以看到,一旦輸入框在失去焦點(diǎn)的時(shí)候,如果里面沒有輸入任何內(nèi)容,每個(gè)輸入框就會(huì)有相應(yīng)的錯(cuò)誤提示,用戶體驗(yàn)很不錯(cuò)。 原文來自: https://jellybool.com/post/programming-with-yii2-exploring-mvc-forms-a... 上一篇文章我們簡(jiǎn)單地實(shí)現(xiàn)了Yii2框架安裝和Hello World,而在這一篇文章當(dāng)中...
摘要:利用渲染后臺(tái)模板后臺(tái)的模板我們采用利用插播一曲是一個(gè)完全響應(yīng)管理模板?;诳蚣?,易定制模板。適合多種屏幕分辨率,從小型移動(dòng)設(shè)備到大型臺(tái)式機(jī)。內(nèi)置了多個(gè)頁面,包括儀表盤郵箱日歷鎖屏登錄及注冊(cè)錯(cuò)誤錯(cuò)誤等頁面。 作者:白狼 出處:http://www.manks.top/yii2_fra... 本文版權(quán)歸作者,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保...
閱讀 2747·2021-09-02 15:11
閱讀 921·2019-08-26 18:18
閱讀 1875·2019-08-26 11:57
閱讀 3332·2019-08-23 16:59
閱讀 2007·2019-08-23 16:51
閱讀 2314·2019-08-23 16:11
閱讀 3135·2019-08-23 14:58
閱讀 1117·2019-08-23 11:34