驗證和受權(Authentication and Authorization)php
對於須要限制某些用戶訪問的網頁,咱們須要使用驗證(Authentication)和受權(Authorization)。 驗證是指覈查一我的是否真的是他本身所聲稱的那我的。這一般須要一個用戶名和密碼, 但也包括任何其餘能夠代表身份的方式,例如一個智能卡,指紋等等。 受權則是找出已經過驗證的用戶是否容許操做特定的資源。 這通常是經過查詢此用戶是否屬於一個有權訪問該資源的角色來判斷的。html
Yii 有一個內置的驗證/受權(auth)框架,用起來很方便,還能對其進行自定義,使其符合特殊的需求。mysql
Yii auth 框架的核心是一個預約義的 用戶(user)應用組件 它是一個實現了 IWebUser 接口的對象。 此用戶組件表明當前用戶的持久性認證信息。咱們能夠經過Yii::app()->user
在任何地方訪問它。react
使用此用戶組件,咱們能夠經過 CWebUser::isGuest 檢查檢查一個用戶是否登錄; 能夠 登陸(login) 或 註銷(logout) 一個用戶;咱們能夠經過CWebUser::checkAccess檢查此用戶是否能夠執行特定的操做;還能夠獲取此用戶的惟一標識(unique identifier)及其餘持久性身份信息。web
爲了驗證一個用戶,咱們定義一個有驗證邏輯的身份類。這個身份類實現IUserIdentity 接口。sql
不一樣的類可能實現不一樣的驗證方式(例如:OpenID,LDAP)。最好是繼承 CUserIdentity,此類是居於用戶名和密碼的驗證方式。數據庫
定義身份類的主要工做是實現IUserIdentity::authenticate方法。在用戶會話中根據須要,身份類可能須要定義別的身份信息express
下面的例子,咱們使用Active Record來驗證提供的用戶名、密碼和數據庫的用戶表是否吻合。咱們經過重寫getId
函數來返回驗證過程當中得到的_id
變量(缺省的實現則是返回用戶名)。在驗證過程當中,咱們還藉助CBaseUserIdentity::setState函數把得到的title
信息存成一個狀態。api
authenticate()
to use the database to validate credentials.CUserIdentity::getId()
method to return the _id
property because the default implementation returns the username as the ID.setState()
(CBaseUserIdentity::setState) method to demonstrate storing other information that can easily be retrieved upon subsequent requests.class UserIdentity extends CUserIdentity { private $_id; public function authenticate() { $record=User::model()->findByAttributes(array('username'=>$this->username)); if($record===null) $this->errorCode=self::ERROR_USERNAME_INVALID; else if($record->password!==md5($this->password)) $this->errorCode=self::ERROR_PASSWORD_INVALID; else { $this->_id=$record->id; $this->setState('title', $record->title); $this->errorCode=self::ERROR_NONE; } return !$this->errorCode; } public function getId() { return $this->_id; } }
做爲狀態存儲的信息(經過調用CBaseUserIdentity::setState)將被傳遞給CWebUser。然後者則把這些信息存放在一個永久存儲媒介上(如session)。咱們能夠把這些信息看成CWebUser的屬性來使用。例如,爲了得到當前用戶的title
信息,咱們可使用Yii::app()->user->title
(這項功能是在1.0.3版本引入的。在以前的版本里,咱們須要使用Yii::app()->user->getState('title')
)。數組
提示: 缺省狀況下,CWebUser用session來存儲用戶身份信息。若是容許基於cookie方式登陸(經過設置 CWebUser::allowAutoLogin爲 true),用戶身份信息將被存放在cookie中。確記敏感信息不要存放(例如 password) 。
使用身份類和用戶部件,咱們方便的實現登陸和註銷。
// 使用提供的用戶名和密碼登陸用戶
$identity=new UserIdentity($username,$password);
if($identity->authenticate())
Yii::app()->user->login($identity);
else
echo $identity->errorMessage;
......
// 註銷當前用戶
Yii::app()->user->logout();
Here we are creating a new UserIdentity object and passing in the authentication credentials (i.e. the$username
and $password
values submitted by the user) to its constructor. We then simply call theauthenticate()
method. If successful, we pass the identity information into the CWebUser::login method, which will store the identity information into persistent storage (PHP session by default) for retrieval upon subsequent requests. If the authentication fails, we can interrogate the errorMessage
property for more information as to why it failed.
Whether or not a user has been authenticated can easily be checked throughout the application by usingYii::app()->user->isGuest
. If using persistent storage like session (the default) and/or a cookie (discussed below) to store the identity information, the user can remain logged in upon subsequent requests. In this case, we don't need to use the UserIdentity class and the entire login process upon each request. Rather CWebUser will automatically take care of loading the identity information from this persistent storage and will use it to determine whether Yii::app()->user->isGuest
returns true or false.
缺省狀況下,用戶將根據session configuration完成一序列inactivity動做後註銷。設置用戶部件的allowAutoLogin屬性爲true和在CWebUser::login方法中設置一個持續時間參數來改變這個行爲。即便用戶關閉瀏覽器,此用戶將保留用戶登錄狀態時間爲被設置的持續時間之久。前提是用戶的瀏覽器接受cookies。
// 保留用戶登錄狀態時間7天
// 確保用戶部件的allowAutoLogin被設置爲true。
Yii::app()->user->login($identity,3600*24*7);
As we mentioned above, when cookie-based login is enabled, the states stored via CBaseUserIdentity::setStatewill be saved in the cookie as well. The next time when the user is logged in, these states will be read from the cookie and made accessible via Yii::app()->user
.
Although Yii has measures to prevent the state cookie from being tampered on the client side, we strongly suggest that security sensitive information be not stored as states. Instead, these information should be restored on the server side by reading from some persistent storage on the server side (e.g. database).
In addition, for any serious Web applications, we recommend using the following strategy to enhance the security of cookie-based login.
When a user successfully logs in by filling out a login form, we generate and store a random key in both the cookie state and in persistent storage on server side (e.g. database).
Upon a subsequent request, when the user authentication is being done via the cookie information, we compare the two copies of this random key and ensure a match before logging in the user.
If the user logs in via the login form again, the key needs to be re-generated.
By using the above strategy, we eliminate the possibility that a user may re-use an old state cookie which may contain outdated state information.
To implement the above strategy, we need to override the following two methods:
CUserIdentity::authenticate(): this is where the real authentication is performed. If the user is authenticated, we should re-generate a new random key, and store it in the database as well as in the identity states via CBaseUserIdentity::setState.
CWebUser::beforeLogin(): this is called when a user is being logged in. We should check if the key obtained from the state cookie is the same as the one from the database.
訪問控制過濾器是檢查當前用戶是否能執行訪問的controller action的初步受權模式。這種受權模式基於用戶名,客戶IP地址和訪問類型。 It is provided as a filter named as "accessControl".
小貼士: 訪問控制過濾器適用於簡單的驗證。須要複雜的訪問控制,須要使用將要講解到的基於角色訪問控制(role-based access (RBAC)).
class PostController extends Controller { public function filters() { return array( 'accessControl', // perform access control for CRUD operations 'postOnly + delete', // we only allow deletion via POST request ); } /** * Specifies the access control rules. * This method is used by the 'accessControl' filter. * @return array access control rules */ public function accessRules() { return array( array('allow', // allow all users to perform 'list' and 'show' actions 'actions'=>array('index','view'), 'users'=>array('*'), ), array('allow', // allow authenticated users to perform any action 'users'=>array('@'), ), array('deny', // deny all users 'users'=>array('*'), ), ); }
訪問規則經過以下的上下文參數設置:
actions: 設置哪一個動做匹配此規則。
users: 設置哪一個用戶匹配此規則。 此當前用戶的name 被用來匹配. 三種設定字符在這裏能夠用:
*
: 任何用戶,包括匿名和驗證經過的用戶。?
: 匿名用戶。@
: 驗證經過的用戶。roles: 設定哪一個角色匹配此規則。 這裏用到了將在後面描述的role-based access control技術。In particular, the rule is applied if CWebUser::checkAccess returns true for one of the roles.提示,用戶角色應該被設置成allow
規則,由於角色表明能作某些事情。
ips: 設定哪一個客戶端IP匹配此規則。
verbs: 設定哪一種請求類型(例如:GET
, POST
)匹配此規則。
expression: 設定一個PHP表達式。它的值用來代表這條規則是否適用。在表達式,你可使用一個叫$user
的變量,它表明的是Yii::app()->user
。這個選項是在1.0.3版本里引入的。
當受權失敗,即,用戶不容許執行此動做,如下的兩種可能將會產生:
若是用戶沒有登陸和在用戶部件中配置了loginUrl,瀏覽器將重定位網頁到此配置URL。
不然一個錯誤代碼401的HTTP例外將顯示。
當配置loginUrl 屬性,能夠用相對和絕對URL。還可使用數組經過CWebApplication::createUrl來生成URL。第一個元素將設置route 爲登陸控制器動做,其餘爲名-值成對形式的GET參數。以下,
array( ...... 'components'=>array( 'user'=>array( // 這其實是默認值 'loginUrl'=>array('site/login'), ), ), )
若是瀏覽器重定位到登陸頁面,並且登陸成功,咱們將重定位瀏覽器到引發驗證失敗的頁面。咱們怎麼知道這個值呢?咱們能夠經過用戶部件的returnUrl 屬性得到。咱們所以能夠用以下執行重定向:
Yii::app()->request->redirect(Yii::app()->user->returnUrl);
基於角色的訪問控制提供了一種簡單而又強大的集中訪問控制。 請參閱維基文章瞭解更多詳細的RBAC與其餘較傳統的訪問控制模式的比較。
Yii 經過其 authManager 組件實現了分等級的 RBAC 結構。 在下文中,咱們將首先介紹在此結構中用到的主要概念。而後講解怎樣定義用於受權的數據。在最後,咱們看看如何利用這些受權數據執行訪問檢查。
在 Yii 的 RBAC 中,一個基本的概念是 受權項目(authorization item)。 一個受權項目就是一個作某件事的許可(例如新帖發佈,用戶管理)。根據其粒度和目標受衆, 受權項目可分爲 操做(operations),任務(tasks)和 角色(roles)。 一個角色由若干任務組成,一個任務由若干操做組成, 而一個操做就是一個許可,不可再分。 例如,咱們有一個系統,它有一個 管理員
角色,它由 帖子管理
和 用戶管理
任務組成。 用戶管理
任務能夠包含 建立用戶
,修改用戶
和 刪除用戶
操做組成。 爲保持靈活性,Yii 還容許一個角色包含其餘角色或操做,一個任務能夠包含其餘操做,一個操做能夠包括其餘操做。
受權項目是經過它的名字惟一識別的。
一個受權項目可能與一個 業務規則 關聯。 業務規則是一段 PHP 代碼,在進行涉及受權項目的訪問檢查時將會被執行。 僅在執行返回 true 時,用戶纔會被視爲擁有此受權項目所表明的權限許可。 例如,當定義一個updatePost(更新帖子)
操做時,咱們能夠添加一個檢查當前用戶 ID 是否與此帖子的做者 ID 相同的業務規則, 這樣,只有做者本身才有更新帖子的權限。
經過受權項目,咱們能夠構建一個 受權等級體系 。在等級體系中,若是項目 A
由另外的項目 B
組成(或者說 A
繼承了 B
所表明的權限),則 A
就是 B
的父項目。 一個受權項目能夠有多個子項目,也能夠有多個父項目。所以,受權等級體系是一個偏序圖(partial-order graph)結構而不是一種樹狀結構。 在這種等級體系中,角色項目位於最頂層,操做項目位於最底層,而任務項目位於二者之間。
一旦有了受權等級體系,咱們就能夠將此體系中的角色分配給用戶。 而一個用戶一旦被賦予一個角色,他就會擁有此角色所表明的權限。 例如,若是咱們賦予一個用戶 管理員
的角色,他就會擁有管理員的權限,包括 帖子管理
和 用戶管理
(以及相應的操做,例如 建立用戶
)。
如今有趣的部分開始了,在一個控制器動做中,咱們想檢查當前用戶是否能夠刪除指定的帖子。 利用 RBAC 等級體系和分配,能夠很容易作到這一點。以下:
if(Yii::app()->user->checkAccess('deletePost')) { // 刪除此帖 }
在咱們準備定義一個受權等級體系並執行訪問權限檢查以前, 咱們須要配置一下 authManager 應用組件。 Yii 提供了兩種受權管理器: CPhpAuthManager 和 CDbAuthManager。前者將受權數據存儲在一個 PHP 腳本文件中然後者存儲在數據庫中。 配置 authManager 應用組件時,咱們須要指定使用哪一個受權管理器組件類, 以及所選受權管理器組件的初始化屬性值。例如:
return array( 'components'=>array( 'db'=>array( 'class'=>'CDbConnection', 'connectionString'=>'sqlite:path/to/file.db', ), 'authManager'=>array( 'class'=>'CDbAuthManager', 'connectionID'=>'db', ), ), );
而後,咱們即可以使用 Yii::app()->authManager
訪問 authManager 應用組件。
定義受權等級體總共分三步:定義受權項目,創建受權項目之間的關係,還要分配角色給用戶。 authManager 應用組件提供了用於完成這三項任務的一系列 API 。
要定義一個受權項目,可調用下列方法之一,具體取決於項目的類型:
創建受權項目以後,咱們就能夠調用下列方法創建受權項目之間的關係:
最後,咱們調用下列方法將角色分配給用戶。
下面的代碼演示了使用 Yii 提供的 API 構建一個受權體系的例子:
$auth=Yii::app()->authManager; $auth->createOperation('createPost','create a post'); $auth->createOperation('readPost','read a post'); $auth->createOperation('updatePost','update a post'); $auth->createOperation('deletePost','delete a post'); $bizRule='return Yii::app()->user->id==$params["post"]->authID;'; $task=$auth->createTask('updateOwnPost','update a post by author himself',$bizRule); $task->addChild('updatePost'); $role=$auth->createRole('reader'); $role->addChild('readPost'); $role=$auth->createRole('author'); $role->addChild('reader'); $role->addChild('createPost'); $role->addChild('updateOwnPost'); $role=$auth->createRole('editor'); $role->addChild('reader'); $role->addChild('updatePost'); $role=$auth->createRole('admin'); $role->addChild('editor'); $role->addChild('author'); $role->addChild('deletePost'); $auth->assign('reader','readerA'); $auth->assign('author','authorB'); $auth->assign('editor','editorC'); $auth->assign('admin','adminD');
創建此受權等級體系後,authManager 組件(例如 CPhpAuthManager, CDbAuthManager) 就會自動加載受權項目。所以,咱們只須要運行上述代碼一次,並不須要在每一個請求中都要運行。
信息: 上面的示例看起來比較冗長拖沓,它主要用於演示的目的。 開發者一般須要開發一些用於管理的用戶界面,這樣最終用戶能夠經過界面更直觀地創建一個受權等級體系。
在定義受權等級體系時,咱們能夠將 業務規則 關聯到一個角色,一個任務,或者一個操做。 咱們也能夠在爲一個用戶分配角色時關聯一個業務規則。 一個業務規則就是一段 PHP 代碼,在咱們執行權限檢查時被執行。 代碼返回的值用來決定是否將角色或分配應用到當前用戶。 在上面的例子中,咱們把一條業務規則關聯到了updateOwnPost
任務。 在業務規則中,咱們簡單的檢查了當前用戶的 ID 是否與指定帖子的做者 ID 相同。$params
數組中的帖子(post)信息由開發者在執行權限檢查時提供。
要執行權限檢查,咱們首先須要知道受權項目的名字。 例如,要檢查當前用戶是否能夠建立帖子,咱們須要檢查他是否擁有 createPost
所表示的權限。 而後咱們調用 CWebUser::checkAccess 執行權限檢查:
if(Yii::app()->user->checkAccess('createPost')) { // 建立帖子 }
若是受權規則關聯了一條須要額外參數的業務規則,咱們也能夠傳遞給它。例如,要檢查一個用戶是否能夠更新帖子, 咱們能夠經過 $params
傳遞帖子的數據:
$params=array('post'=>$post); if(Yii::app()->user->checkAccess('updateOwnPost',$params)) { // 更新帖子 }
注意: 默認角色功能從 1.0.3 版本起可用。
許多 Web 程序須要一些能夠分配給系統中全部或大多數用戶的比較特殊的角色。 例如,咱們可能想要分配一些權限給全部已經過身份驗證的用戶。若是咱們特地指定並存儲這些角色分配,就會引發不少維護上的麻煩。 咱們能夠利用 默認角色 解決這個問題。
默認角色就是一個隱式分配給每一個用戶的角色,這些用戶包括經過身份驗證的用戶和遊客。 咱們不須要顯式地將其分配給一個用戶。 當 CWebUser::checkAccess 被調用時,將會首先檢查默認的角色,就像它已經被分配給這個用戶同樣。
默認角色必須定義在 CAuthManager::defaultRoles 屬性中。 例如,下面的配置聲明瞭兩個角色爲默認角色:authenticated
和 guest
。
return array( 'components'=>array( 'authManager'=>array( 'class'=>'CDbAuthManager', 'defaultRoles'=>array('authenticated', 'guest'), ), ), );
因爲默認角色會被分配給每一個用戶,它通常須要關聯一個業務規則以肯定角色是否真的要應用到用戶。 例如,下面的代碼定義了兩個角色, authenticated
和 guest
,很高效地分別應用到了已經過身份驗證的用戶和遊客用戶。
$bizRule='return !Yii::app()->user->isGuest;'; $auth->createRole('authenticated', 'authenticated user', $bizRule); $bizRule='return Yii::app()->user->isGuest;'; $auth->createRole('guest', 'guest user', $bizRule);
http://blog.sina.com.cn/s/blog_907043b30101emfk.html
如何建立數據庫已經role-base
yii下,filters()和accessControl()是YII基本的訪問控制體系,
public function filters(){
return array(
'accessControl',
);
}
public function accessControl(){
return array(
array(
'allow', //allow or deny 容許或者拒絕
'controllers' => array('controllersList'), //對控制器進行訪問控制
'actions' => array('actionsList'), //對action進行訪問控制
'users' => array('usersList'), //對用戶
'roles' => array('roles'), //對角色
'ips' => array('ip 地址'), //對客戶端地址
'verbs' => array('GET','POST'), //對客戶端的請求方式
'expression' => '' //對錶達式(通常是業務邏輯)
'message' => 'thank your access', //錯誤信息提示,通常是deny時用到
),
array(....),
....
array('deny', users => array('*')),
);
}
好了,有了以上的訪問控制,咱們針對上面的roles進行討論RBAC。
Yii的RBAC是基於一個組件authManager的,能夠先在main。php中配置authManager
authManger分爲基於數據庫的和基於PHP腳本的,通常若是你的應用程序基於數據庫(mysql或者pgsql),最好把authManger配置爲CDbAuthManger,而不是CPhpAuthManger。
...
'authManager' => array(
'class' => 'CDbAuthManager',
'connectionID' => 'db',
),
'db' => array(...),
...
配置好了之後,須要在數據庫中增長3個存放RBAC規則的表:
AuthItem -- 存放創建的受權項目(role、task或者opration)
AuthItemChild -- 存放受權項目的繼承關係
AuthAssignMent -- 存放用戶和受權項目的關係表
CREATE TABLE `authitem` ( `name` varchar(64) NOT NULL, `type` int(11) NOT NULL, `description` text, `bizrule` text, `data` text, PRIMARY KEY (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `authitemchild` ( `parent` varchar(64) NOT NULL, `child` varchar(64) NOT NULL, PRIMARY KEY (`parent`,`child`), KEY `child` (`child`), CONSTRAINT `authitemchild_ibfk_1` FOREIGN KEY (`parent`) REFERENCES `authitem` (`name`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `authitemchild_ibfk_2` FOREIGN KEY (`child`) REFERENCES `authitem` (`name`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `authassignment` ( `itemname` varchar(64) NOT NULL, `userid` varchar(64) NOT NULL, `bizrule` text, `data` text, PRIMARY KEY (`itemname`,`userid`), CONSTRAINT `authassignment_ibfk_1` FOREIGN KEY (`itemname`) REFERENCES `authitem` (`name`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
建好表之後,就能夠用Yii提供的authManger組件的API創建相關的受權項目,並指定受權關係了。
下面是一個例子:
下面作一個實例:
class AuthManagerController extends Controller { public function actionIndex(){ $auth = Yii::app()->authManager; if ($auth !== NULL){ $auth->clearAll(); //create roles $roleOwner = $auth->createRole('owner'); $roleReader = $auth->createRole('reader'); $roleMember = $auth->createRole('member'); $roleBlackList = $auth->createRole('blackList'); //create operations //issues $auth->createOperation('createIssue', 'create issue in project'); $auth->createOperation('readIssue', 'read issue'); $auth->createOperation('updateIssue', 'update issue'); $auth->createOperation('deleteIssue', 'delete issue'); //projects $auth->createOperation('createProject', 'create a new project'); $auth->createOperation('readProject', 'read project'); $auth->createOperation('updateProject', 'update project'); $auth->createOperation('deleteProject', 'delete project'); //users $auth->createOperation('createUser', 'create a new user'); $auth->createOperation('readUser', 'read user'); $auth->createOperation('updateUser', 'update user'); $auth->createOperation('deleteUser', 'delete user'); //authorization $roleReader->addChild('readIssue'); $roleReader->addChild('readProject'); $roleReader->addChild('readUser'); $roleMember->addChild('reader'); $roleMember->addChild('createIssue'); $roleMember->addChild('updateIssue'); $roleMember->addChild('deleteIssue'); $roleOwner->addChild('reader'); $roleOwner->addChild('member'); $roleOwner->addChild('createProject'); $roleOwner->addChild('updateProject'); $roleOwner->addChild('deleteProject'); $roleOwner->addChild('createUser'); $roleOwner->addChild('updateUser'); $roleOwner->addChild('deleteUser'); //assign //此時,在Issue中的rules中設置view和index的roles=>array('member'),無論是什麼用戶,都沒法訪問這兩個action $userAdmin = User::model()->findByAttributes(array('username' => 'admin')); $auth->assign('owner', $userAdmin->id); $auth->assign('member', $userAdmin->id); //將用戶名爲admin(id=3)指定爲member角色,這樣就能夠訪問了。 $auth->assign('reader', $userAdmin->id); $userDemo = User::model()->findByAttributes(array('username' => 'demo')); $auth->assign('member', $userDemo->id); //將用戶名爲admin(id=3)指定爲member角色,這樣就能夠訪問了。 $auth->assign('reader', $userDemo->id); //將用戶名爲demo(id=4)指定爲reader角色 $userDemo2 = User::model()->findByAttributes(array('username' => 'demo2')); $auth->assign('reader', $userDemo2->id); //將用戶名爲demo(id=4)指定爲reader角色 $userBlackList = User::model()->findByAttributes(array('username' => 'demo3')); $auth->assign('blackList', $userBlackList->id); }else{ $message = 'Please config your authManage as a compontion in main.php'; throw new CHttpException(0, $message); } } }
執行上面的文件,創建受權關係之後,更新accessRules爲: public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('@'), 'roles' => array('member', 'owner', 'reader'), ), array('allow', // allow authenticated user to perform 'create' and 'update' actions 'actions'=>array('create','update'), 'users'=>array('@'), 'roles' => array('member', 'owner'), ), array('allow', // allow admin user to perform 'admin' and 'delete' actions 'actions'=>array('admin','delete'), 'users'=>array('@'), 'roles' => array('owner'), ), array('deny', // deny all users 'users'=>array('*'), ), ); } 就是把剛剛創建的受權項目加入到訪問控制列表中。
另一個例子 $auth = Yii::app()->authManger; $roleManager = $auth->createRole('manager'); //創建一個角色 $auth->createTask('projectManager'); //創建任務 $auth->createTask('userManager'); $auth->createOpration('createProject'); //創建操做 $auth->createOpration('updateProject'); $auth->createOpration('deleteUser'); $user = User::model()->findByPk('1'); //檢索用戶 $roleManager->addChild('projectManager'); //爲角色受權任務 $roleManager->addChild('updateProject');//爲角色受權操做 $auth->assign('manager', $user->id);//指定用戶權限
轉自:http://blog.chinaunix.net/uid-395468-id-185860.html
-------------------------------------------------------------------------------------
YII非rbac通用權限,controller中加權限過濾器beforeaction
public function purview($module, $control, $action) { if (!$this->checkPower($action, $control, module)) { throw new CHttpException(403, '您沒有訪問權限!'); Yii::app()->end(); } } // CGRIDVIEW buttonID 'visible' =>'$this->grid->controller->checkPower("delete")', public function checkPower($action, $contrl = null, $module = null) { if ($contrl === null) { $contrl = $this->getId(); } if ($module === null && $this->getModule()) { $module = $this->getModule()->getId(); } return Privilege::model()->checkPower($module, $contrl, $action); } public function beforeAction($action) { $contrl = $this->getId(); $actionId = $action->getId(); $route = $contrl . '/' . $actionId; if (!in_array($route, array('site/login', 'site/error', 'site/logout')) && Yii::app()->user->id != 1) { $module = null; if ($action && $this->getModule()) { $module = $this->getModule()->getId(); } $this->purview($module, $contrl, $actionId); } return parent::beforeAction($action); }
在這裏的visible表達式中設置調用$this->checkPower('操做名');就能夠隱藏沒有權限訪問的菜單了
上面的好像有問題,爲何還要調用parent::beforeAction呢,直接返回ture和false就能夠。返回true就執行。
----------------------------------
一篇文章:
開始準備
Yii提供了強大的配置機制和不少現成的類庫。在Yii中使用RBAC是很簡單的,徹底不須要再寫RBAC代碼。因此準備工做就是,打開編輯器,跟我來。
設置參數、創建數據庫
在配置數組中,增長如下內容:
那這三個數據表怎麼創建呢?很簡單,去看framework/web/auth/schema.sql。注意要和你的自定義的表名稱對應起來。好比SQL文件中的AuthItem你要修改成pre_auth_item。而後在數據庫中運行這個SQL文件中的語句。
瞭解概念
你可能要問,剩下的代碼呢?我告訴你,沒有啦。RBAC系統就這樣創建起來了。可是爲了使用它,你須要瞭解它的運行機制。我會盡可能講的囉嗦一點……(官方的RBAC文檔在這裏,可是我曾經看了4-5遍才明白。)
三個概念
你須要瞭解的是,受權項目可分爲operations(行動),tasks(任務)和 roles(角色)。
一個用戶擁有一個或者多個角色,好比,咱們這裏有三個角色:銀行行長、銀行職員、顧客。咱們假設:
* 張行長 有角色:銀行行長、銀行職員、顧客(人家本身能夠存錢嘛)。
* 王職員 有角色:銀行職員、顧客。
* 小李 有角色:顧客。
那麼,相應的,只要顧客能夠作的事情,小李就能夠作,王職員和張行長也能夠。銀行職員能夠作的事情,王職員和張行長均可以作,小李就不能夠了。
好比,一個「顧客」能夠存錢,那麼擁有「顧客」角色的張行長、王職員、小李均可以存錢。「銀行職員」能夠打印顧客的交易記錄,那麼有「銀行職員」角色的張行長和王職員均可以,而小李不行,必須找一個有「銀行職員」角色的人才能夠打印詳細的交易記錄。一個「銀行行長」才能夠進入銀行錢庫提錢,那麼只有張行長能夠,由於它纔有「銀行行長」的角色。
這就是基於角色的認證體系,簡稱RBAC。
角色的繼承
角色是能夠繼承的,好比咱們規定以下:
* 凡是「銀行行長」都是「銀行職員」,也就是說,只要銀行職員能夠作的事情,銀行行長均可以作。
* 凡是「銀行職員」都是顧客,同上,顧客能夠作的事情銀行職員也能夠作。
那麼角色關係就變成了:
* 張行長 有角色:銀行行長。
* 王職員 有角色:銀行職員。
* 小李 有角色:顧客。
這樣更簡單了,這就是角色的繼承。
任務的繼承
一個任務(task)是能夠包含另一個任務的,咱們舉個例子,好比「進入銀行」。
咱們設定「顧客」這個角色有「進入銀行」的權限。也就是說,「顧客」能夠執行「進入銀行」的任務。接下來,咱們假設「進入櫃檯」是進入銀行的父權限,也就是說,「進入櫃檯」包含「進入銀行」。只要能「進入櫃檯」的人均可以「進入銀行」。咱們把「進入櫃檯」這個任務權限給「銀行職員」。
那麼從角色上來講,王職員能夠進入銀行,由於王職員的角色是「銀行職員」,而「銀行職員」包含了「顧客」的角色。那麼「顧客」能夠進行的「任務」對於「銀行職員」來講也是能夠進行的。而「顧客」能夠「進入銀行」,那麼王職員也能夠「進入銀行」。這是角色的繼承帶來的。
咱們再假設有個趙領導,是上級領導,能夠進入櫃檯進行視察。那麼,咱們的任務關係是:
* 趙領導 有任務:進入櫃檯。
那麼,趙領導就能夠「進入銀行」。由於「進入銀行」是被「進入櫃檯」包含的任務。只要能夠執行「進入櫃檯」的人均可以執行「進入銀行」。這就是任務的繼承。
關於行動
行動是不可劃分的一級。也就是說。而一個行動是不能包含其餘行動的。假設咱們有個行動叫「從銀行倉庫中提錢」。咱們把這個行動做包含「進入櫃檯」。那麼只要能夠執行「從銀行倉庫中提錢」的角色均可以執行「進入櫃檯」這個任務。
三者關係
* 一個角色能夠包含另一個或者幾個角色。
* 一個角色能夠包含另一個或者幾個任務。
* 一個角色能夠包含另一個或者幾個行動。
*
* 一個任務能夠包含另一個或者幾個任務。
* 一個任務能夠包含另一個或者幾個行動。
*
* 一個行動只能被角色或者任務包含,行動是不能夠包含其餘,也不可再分。
這樣,就造成了一個權限管理體系。關於「任務」和「行動」,你沒必要思考其字面上的意義。這二者就是造成兩層權限。
進行賦權
咱們創建了RBAC權限管理,就須要進行對權限的WEB管理。這些就須要你本身寫代碼了。
根據不一樣種類的項目調用下列方法之必定義受權項目:
* CAuthManager::createRole
* CAuthManager::createTask
* CAuthManager::createOperation
一旦咱們擁有一套受權項目,咱們能夠調用如下方法創建受權項目關係:
* CAuthManager::addItemChild
* CAuthManager::removeItemChild
* CAuthItem::addChild
* CAuthItem::removeChild
最後,咱們調用下列方法來分配角色項目給各個用戶:
* CAuthManager::assign
* CAuthManager::revoke
下面咱們將展現一個例子是關於用所提供的API創建一個受權等級:
也就是說,你須要本身寫一個管理界面,來列出你的角色、任務、行動,而後能夠在這個界面上進行管理。好比增長、刪除、修改。
權限檢查
假設你在你的管理界面進行了賦權,那麼能夠在程序裏面進行權限檢查:
上面的代碼就檢查了用戶是否能夠執行「createPost」,這createPost多是一個任務,也能夠是一個行動。
其餘的
對於不少說Yii權限體系RBAC很差用的人其實都沒有看懂文檔。綜合個人體驗,我感受Yii框架的RBAC是我用過的框架裏面最好用的。並且是須要本身寫代碼最少的。
Yii的RBAC有更加高級的用法,好比「業務規則」,「默認角色」。你能夠去參考官方文檔。
我知道,會有部分人仍舊不理解RBAC,或者不會用Yii的RBAC。沒有關係,你能夠在下方的評論框裏提問。
happy Yii !
------------------------------------------------------------------------
。雖然authMangner組件實現了rbac,可是沒有實現可視化編輯管理。目前官方有Srbac 和 Right兩個比較好的擴展模塊,咱們用它們很是方便的可視化管理角色(roles),任務(tasks),操做(operations)。
參考:http://blog.sina.com.cn/s/blog_92863deb01014ac0.html
http://www.howzhi.com/course/2519/lesson/35392
http://www.open-open.com/lib/view/open1356679026838.html
http://www.cnblogs.com/hi-bazinga/archive/2012/05/15/2502194.html