Yii::app()->user
在任何地方访问它。
定义身份类 (Defining Identity Class)
不同的类可能实现不同的验证方式(例如:OpenID,LDAP)。最好是继承 CUserIdentity,此类是居于用户名和密码的验证方式。定义身份类的主要工作是实现IUserIdentity::authenticate方法。在用户会话中根据需要,身份类可能需要定义别的身份信息
应用实例
下面的例子,我们使用Active Record来验证提供的用户名、密码和数据库的用户表是否吻合。我们通过重写getId
函数来返回验证过程中获得的_id
变量(缺省的实现则是返回用户名)。在验证过程中,我们还借助CBaseUserIdentity::setState函数把获得的title
信息存成一个状态。
- 实现这个方法
authenticate()
来使用数据库数据进行验证。 - 重写
CUserIdentity::getId()
方法可以返回_id
属性, 因为默认是返回username而不是id。 - 使用
setState()
(CBaseUserIdentity::setState) 方法来设置一个信息保存起来,以便检索后面的请求。 - 下面的这个类默认存在在protected/components/UserIdentity.php
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;
}}
title
信息,我们可以使用
Yii::app()->user->title
(这项功能是在1.0.3版本引入的。在之前的版本里,我们需要使用
Yii::app()->user->getState('title')
)。
登录和注销(Login and Logout)
使用身份类和用户部件,我们方便的实现登录和注销。
// 使用提供的用户名和密码登录用户$identity=new UserIdentity($username,$password);
if($identity->authenticate())
Yii::app()->user->login($identity);
else
echo $identity->errorMessage;
......
// 注销当前用户Yii::app()->user->logout();
Yii::app()->user->isGuest
. 如果它返回false表示未登陆,如果返回true则表示已经把身份信息存储到了存储器中。
缺省情况下,用户将根据session configuration完成一序列inactivity动作后注销。设置用户部件的allowAutoLogin属性为true和在CWebUser::login方法中设置一个持续时间参数来改变这个行为。即使用户关闭浏览器,此用户将保留用户登陆状态时间为被设置的持续时间之久。前提是用户的浏览器接受cookies。
// 保留用户登陆状态时间7天// 确保用户部件的allowAutoLogin被设置为true。Yii::app()->user->login($identity,3600*24*7);
class PostController extends CController{
......
public function filters()
{
return array(
'accessControl',
);
}}
在上面,设置的access control过滤器将应用于PostController
里每个动作。过滤器具体的授权规则通过重载控制器的CController::accessRules方法来指定。
class PostController extends CController{
......
public function accessRules()
{
return array(
array('deny',
'actions'=>array('create', 'edit'),
'users'=>array('?'),
),
array('allow',
'actions'=>array('delete'),
'roles'=>array('admin'),
),
array('deny',
'actions'=>array('delete'),
'users'=>array('*'),
),
);
}}
上面设定了三个规则,每个用个数组表示。数组的第一个元素不是'allow'
就是'deny'
,其他的是名-值成对形式设置规则参数的。上面的规则这样理解:create
和edit
动作不能被匿名执行;delete
动作可以被admin
角色的用户执行;delete
动作不能被任何人执行。
allow
,则动作可执行;如果是
deny
,不能执行;如果没有规则匹配,动作可以执行。
为了确保某类动作在没允许情况下不被执行,设置一个匹配所有人的deny
规则在最后,类似如下:
return array(
// ... 别的规则...
// 以下匹配所有人规则拒绝'delete'动作
array('deny',
'action'=>'delete',
),
);
因为如果没有设置规则匹配动作,动作缺省会被执行。
访问规则通过如下的上下文参数设置:
-
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);
管理员
角色,它由
帖子管理
和
用户管理
任务组成。
用户管理
任务可以包含
创建用户
,
修改用户
和
删除用户
操作组成。 为保持灵活性,Yii 还允许一个角色包含其他角色或操作,一个任务可以包含其他操作,一个操作可以包括其他操作。
A
由另外的项目
B
组成。
则
A
就是
B
的父项目。 一个授权项目可以有多个子项目,也可以有多个父项目。因此,授权等级体系是一个偏序图(partial-order graph)结构而不是一种树状结构。 在这种等级体系中,角色项目位于最顶层,操作项目位于最底层,而任务项目位于两者之间。
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) 就会自动加载授权项目。因此,我们只需要运行上述代码一次,并不需要在每个请求中都要运行。
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);