Yii入门,登录

时间:2024-01-18 23:51:44

验证和授权在页面需要限制访问时用到。验证就是确认某人就是他所声称的那个人。通常涉及到用户名和密码,但也包含其他方式,例如智能卡,指纹等。授权是在验证用户后,查明他是否被允许管理指定的资源。通常判断他是否是有权访问资源的角色的成员。

Yii 有一个内置的验证/授权框架,它易于使用且可定制。

Yii 认证框架的核心是预声明的用户组件,它是一个实现 IWebUser 接口的对象。用户组件代表了当前用户的持久身份信息。可以使用 Yii::app()->user 来访问。

使用用户组件,可以使用 CWebUser::isGuest 检查一个用户是否已经登录;我们可以登录或者注销一个用户; 调用 CWebUser::checkAccess 可以检查用户是否可以执行特定的操作; 也可以得到用户的唯一身份和另外的持久身份信息。

定义身份类

如之前所说, 验证是确认用户的身份。典型的网络应用验证通常是使用用户名和密码的组合来确认用户的身份。然而,也可以包含其他的方法。为了掩饰兼容各种验证方法, Yii 认证框架引入了身份类。

我们定义一个身份类,它含有实际的验证逻辑。身份类应当实现 IUserIdentity 接口。不同的身份类可以实现不同的验证方法 (例如 OpenID, LDAP, Twitter OAuth, Facebook Connect). 推荐扩展 CUserIdentity 编写你自己的类,CUserIdentity 是使用用户名和密码这种验证方法的基类。

定义身份类最主要的工作是实现 [IUserIdentity::authenticate] 方法. 这个方法封装了验证的逻辑细节。在身份类中也可以声明额外的身份信息。

例子
在下面的例子中,我们使用一个身份类来演示使用数据库方法来验证。这是非常典型的方法。用户需要输入用户名和密码到登录表单中,然后我们验证这些账号信息,使用 ActiveRecord ,向数据库中的表来查询。我们需要演示的是

  • 实现 authenticate() 方法来根据数据库验证账号信息.
  • 重写 CUserIdentity::getId() 方法来返回 _id 属性,因为默认返回用户名作为 ID.
  • 使用 setState() (CBaseUserIdentity::setState) 方法来演示储存其他信息,这些信息可以在随后的访问被轻松获取
<?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;
}
}
?>

下个小结的登录和注销中,我们将看到把这个身份类放在用户的登录方法中。任何储存在状态中的信息 (使用 CBaseUserIdentity::setState) 将被传递给 CWebUser, 它们被保存到持久存储中,例如 session. 这些信息可以作为 CWebUser 的属性被访问。在我们的例子汇总,使用 $this->setState(‘title’,$record->title) 存储用户 title 信息. 在登录完成之后,可以使用 Yii::app()->user->title 得到当前用户的 title 信息。

信息: CWebUser 默认使用 session 作为用户身份信息的持久存储方式。若启用了基于 cookie 的登录 (通过设置 CWebUser::allowAutoLogin 为 true), 用户身份也可以被保存在 cookie 中。一定不要声明敏感信息 (例如密码) 为 persistent.

登录和注销

现在已经看到了创建一个用户身份的例子,我们使用它来简化登录和注销动作。如下代码展示了它们如何被实现的:

<?php
// Login a user with the provided username and password.
$identity=new UserIdentity($username,$password);
if($identity->authenticate())
Yii::app()->user->login($identity);
else
echo $identity->errorMessage;
......
// Logout the current user
Yii::app()->user->logout();
?>

这里我们创建了一个 UserIdentity 对象并传递账号信息 (也就是用户提交的 $username 和 $password ) 到它的构造器中. 然后我们只需调用 authenticate() 方法. 若成功,传递身份信息到 CWebUser::login 方法,在此方法中身份信息被存储到持久存储 (默认是 PHP session ) . 若验证失败, 我们可以查询 errorMessage 属性来了解为何失败.

判断一个用户是否登录非常简单,使用 Yii::app()->user->isGuest 即可. 若使用持久存储如 session (默认地) 和/或 cookie (下面讨论) 来存储身份信息, 用户在随后的请求中保持已登录状态. 这样,我们无需为每次请求使用 UserIdentity 类和完整的登录验证. CWebUser 将自动从持久存储中载入身份信息,用它们来检测Yii::app()->user->isGuest 返回的是 true 还是 false.

基于 cookie 的登录

默认情况下, 用户在一段闲置期限后将被注销, 取决于 session 配额. 为了改变这个行为, 我们可以设置 user 组件的 allowAutoLogin 属性为 true 并传递 duration 参数到 CWebUser::login 方法中. 在指定的期限内用户仍然处于登录状态,即使他关闭了浏览器窗口 注意此特征需要用户的浏览器接受 cookie.

<?php
// Keep the user logged in for 7 days.
// Make sure allowAutoLogin is set true for the user component.
Yii::app()->user->login($identity,3600*24*7);
?>

如之前所述,当启用了基于 cookie 的登录, 通过 CBaseUserIdentity::setState 存储的状态将也保存在 cookie 中. 下次用户登录时, 这些状态从 cookie 中读取,并且可以使用 Yii::app()->user 来访问。

虽然 Yii 有方法来防止状态 cookie 在客户端被篡改, 我们强烈建议安全敏感信息不要储存为状态. 而是选择存储在服务器端,从服务器端的持久存储中读取 (例如数据库).

此外, 位于要求较高的网络应用,我们建议使用如下策略来增强基于 cookie 登录的安全性:

  • 当用户填写登录表单后成功登录, 在 cookie 状态和服务器端的持久存储(如数据库)中生成并存储一个随机 key .
  • 在随后的访问中, 当通过 cookie 信息实现验证后, 我们对比这两个随机 key 来确保登录前他们是一致的。
  • 若用户通过表单再次登录, key 需要重新生成.

通过使用上面的策略, 我们消除了这种可能性:一个用户可以重新使用旧的包含过期 state 信息的 state cookie。

为了实现上面的策略, 我们需要重写如下两个方法:

    • CUserIdentity::authenticate(): 这里是认证真正执行的地方. 若用户被认证, 我们应当重新生成一个新的随机 key, 并把它存储到数据库以及身份状态中( 通过CBaseUserIdentity::setState).
    • CWebUser::beforeLogin(): 它在用户登录时被调用. 我们应当检查 state cookie 中的 key 是否和数据库中的是相同的

在下面的例子中,我们使用一个身份类来演示使用数据库方法来验证。这是非常典型的方法。用户需要输入用户名和密码到登录表单中,然后我们验证这些账号信息,使用 ActiveRecord ,向数据库中的表来查询。我们需要演示的是

  • 实现 authenticate() 方法来根据数据库验证账号信息.
  • 重写 CUserIdentity::getId() 方法来返回 _id 属性,因为默认返回用户名作为 ID.
  • 使用 setState() (CBaseUserIdentity::setState) 方法来演示储存其他信息,这些信息可以在随后的访问被轻松获取

<?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;
    }
}
?>