【Yii】Authentication (2)
【Yii】Authentication (1)中讨论了Yii进行身份验证的流程,并且实现了通过数据库中的用户信息来进行验证的功能。这一篇将讨论如何实现更复杂的验证例程,涉及邮箱验证、不同的用户角色等等。
在默认情况下,Yii使用cookies来保存用户信息。在大多数情况下是没有问题的,但是如果涉及到一些敏感信息,则须使用sessions。例如用户的ID或role,如果被cookies保存到客户端,那么用户可以很容易地修改,比如把role的值从“user”改成“admin”,那么本来的普通用户现在就能拥有管理员的权限,这必然是不能被接受的。
所以,我们首先把cookies的功能禁用。通过修改配置文件protected/config/main.php:
'user'=>array( // enable cookie-based authentication 'allowAutoLogin'=>true, ),
将这一行注释掉或者改成false即可。
接下来修改登录的form(protected/views/site/login.php),默认的view是这样的:
要将Hint和“Remember Me”给去掉,并且我们将使用Email作为登录名,而不是username。
再往下就是修改Model类LoginForm(protected/models/LoginForm.php),该类定义的一些变量跟login form直接相关,所以$username要改成$email,别忘了attributeLabels()中也要做相应修改。另外$rememberMe要删除。
接下来修改rules(),如下:
public function rules() { return array( array('email, password', 'required'), array('email', 'email'), array('password', 'authenticate'), ); }
authenticate()中的username都要改成email,要注意的是,此方法中调用UserIdentity::authenticate(),因为UserIdentity继承自CBaseUserIdentity,所以其中的一些定义如ERROR_USERNAME_INVALID不便改为ERROR_EMAIL_INVALID,所以这里我们认为email和username是同义的。
所以LoginForm中的authenticate()做如下部分修改:
$identity=new UserIdentity($this->username,$this->password); $identity=new UserIdentity($this->email,$this->password); switch($identity->errorCode) { case UserIdentity::ERROR_NONE: Yii::app()->user->login($identity); break; case UserIdentity::ERROR_USERNAME_INVALID: $this->addError('email','Email address is incorrect.'); break; default: // UserIdentity::ERROR_PASSWORD_INVALID $this->addError('password','Password is incorrect.'); break; }
最后,我们来修改protected/components/UserIdentity.php,也是最重要的部分。
先贴代码:
public function authenticate() { $user = User::model()->findByAttributes(array('email'=>$this->username)); if ($user===null) { // No user found! $this->errorCode=self::ERROR_USERNAME_INVALID; } else if ($user->password !== SHA1($this->password) ) { //Invalid password! $this->errorCode=self::ERROR_PASSWORD_INVALID; } else { // Okay! $this->errorCode=self::ERROR_NONE; // Store the role in a session: $this->setState('role', $user->role); } return !$this->errorCode; }
有一个地方值得注意一下,即通过setState()方法将用户的role储存在session中,完成这个操作后,我们可以通过Yii::app()->user->role来获取用户的role。当然,也可以为ID做相同的处理,但是内嵌的验证已经包含了getId()方法,返回用户的标识符,默认返回username。可以通过override重写方法使其返回ID。
先在UserIdentity中创建私有变量$_id:
class UserIdentity extends CUserIdentity { // Need to store the user's ID: private $_id;
验证成功(else语句)时将用户ID复制给该变量:
$this->_id = $user->id;
最后重写getId():
public function getId() { return $this->_id; }
这样用户的ID就可以通过Yii::app()->user->id获得了。