驗證和授權(Authentication and Authorization)
對於需要限制某些用戶訪問的網頁,我們需要使用驗證(Authentication)和授權(Authorization)。 驗證是指核查一個人是否真的是他自己所聲稱的那個人。這通常需要一個用戶名和密碼, 但也包括任何其他可以表明身份的方式,例如一個智能卡,指紋等等。 授權則是找出已通過驗證的用戶是否允許操作特定的資源。 這一般是通過查詢此用戶是否屬於一個有權訪問該資源的角色來判斷的。
Yii 有一個內置的驗證/授權(auth)框架,用起來很方便,還能對其進行自定義,使其符合特殊的需求。
Yii auth 框架的核心是一個預定義的 用戶(user)應用組件 它是一個實現了 IWebUser 接口的對象。 此用戶組件代表當前用戶的持久性認證信息。我們可以通過Yii::app()->user
在任何地方訪問它。
使用此用戶組件,我們可以通過 CWebUser::isGuest 檢查檢查一個用戶是否登陸; 可以 登錄(login) 或 注銷(logout) 一個用戶;我們可以通過CWebUser::checkAccess檢查此用戶是否可以執行特定的操作;還可以獲取此用戶的唯一標識(unique identifier)及其他持久性身份信息。
1. 定義身份類 (Defining Identity Class)
為了驗證一個用戶,我們定義一個有驗證邏輯的身份類。這個身份類實現IUserIdentity 接口。
不同的類可能實現不同的驗證方式(例如:OpenID,LDAP)。最好是繼承 CUserIdentity,此類是居於用戶名和密碼的驗證方式。
定義身份類的主要工作是實現IUserIdentity::authenticate方法。在用戶會話中根據需要,身份類可能需要定義別的身份信息
應用實例
下面的例子,我們使用Active Record來驗證提供的用戶名、密碼和數據庫的用戶表是否吻合。我們通過重寫getId
函數來返回驗證過程中獲得的_id
變量(缺省的實現則是返回用戶名)。在驗證過程中,我們還借助CBaseUserIdentity::setState函數把獲得的title
信息存成一個狀態。
- The implementation of the
authenticate()
to use the database to validate credentials. - Overriding the
CUserIdentity::getId()
method to return the_id
property because the default implementation returns the username as the ID. - Using the
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) 。
2. 登錄和注銷(Login and Logout)
使用身份類和用戶部件,我們方便的實現登錄和注銷。
// 使用提供的用戶名和密碼登錄用戶
$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.
基於Cookie 的登錄
缺省情況下,用戶將根據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.
3. 訪問控制過濾器(Access Control Filter)
訪問控制過濾器是檢查當前用戶是否能執行訪問的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版本里引入的。
授權處理結果(Handling Authorization Result)
當授權失敗,即,用戶不允許執行此動作,以下的兩種可能將會產生:
-
如果用戶沒有登錄和在用戶部件中配置了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);
4. 基於角色的訪問控制(Role-Based Access Control)
基於角色的訪問控制提供了一種簡單而又強大的集中訪問控制。 請參閱維基文章了解更多詳細的RBAC與其他較傳統的訪問控制模式的比較。
Yii 通過其 authManager 組件實現了分等級的 RBAC 結構。 在下文中,我們將首先介紹在此結構中用到的主要概念。然后講解怎樣定義用於授權的數據。在最后,我們看看如何利用這些授權數據執行訪問檢查。
概覽(Overview)
在 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')) { // 刪除此帖 }
5. 配置授權管理器(Authorization Manager)
在我們准備定義一個授權等級體系並執行訪問權限檢查之前, 我們需要配置一下 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 應用組件。
6. 定義授權等級體系
定義授權等級體總共分三步:定義授權項目,建立授權項目之間的關系,還要分配角色給用戶。 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) 就會自動加載授權項目。因此,我們只需要運行上述代碼一次,並不需要在每個請求中都要運行。
信息: 上面的示例看起來比較冗長拖沓,它主要用於演示的目的。 開發者通常需要開發一些用於管理的用戶界面,這樣最終用戶可以通過界面更直觀地建立一個授權等級體系。
7. 使用業務規則
在定義授權等級體系時,我們可以將 業務規則 關聯到一個角色,一個任務,或者一個操作。 我們也可以在為一個用戶分配角色時關聯一個業務規則。 一個業務規則就是一段 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代碼。所以准備工作就是,打開編輯器,跟我來。
設置參數、建立數據庫
在配置數組中,增加以下內容:
‘components‘ => array(
//……
‘authManager‘=>array(
‘class‘=>‘CDbAuthManager‘,//認證類名稱
‘defaultRoles‘=>array(‘guest‘),//默認角色
‘itemTable‘ => ‘pre_auth_item‘,//認證項表名稱
‘itemChildTable‘ => ‘pre_auth_item_child‘,//認證項父子關系
‘assignmentTable‘ => ‘pre_auth_assignment‘,//認證項賦權關系
),
//……
那這三個數據表怎么建立呢?很簡單,去看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建立一個授權等級:
$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');
也就是說,你需要自己寫一個管理界面,來列出你的角色、任務、行動,然后可以在這個界面上進行管理。比如增加、刪除、修改。
權限檢查
假設你在你的管理界面進行了賦權,那么可以在程序里面進行權限檢查:
if( Yii::app()->user->checkAccess('createPost') )
{
// 這里可以顯示表單等操作
} else {
// 檢查沒有通過的可以跳轉或者顯示警告
}
上面的代碼就檢查了用戶是否可以執行“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