yii2的认证体系

背景知识:

  1. 我们常说的用户相关的安全操作主要就三块:认证,授权,加密。
  2. 本文主要介绍基于yii2的user的组件来实现用户的认证。
  3. 用户认证的流程:根据用户名查询数据库的记录,然后将用户输入的密码加密之后和数据库的记录进行对比,如果相等则登录成功,登录成功之后,将用户的信息存入到session中。以上就是一个简单的认证流程,当然其中你可以加入记住我等功能。由于yii2框架给我们封装好了以上的操作,因此就不需要造轮子了,接下来介绍user组件的使用。

1.在使用user组件之前我们需要先做一些准备工作:

首先需要我们的模型类实现接口 IdentityInterface,其次我们需要在web.php中配置user组件,以下给出案例:

#以下是最简单的事例,user组件管理的模型必须实现以下五个方法
class User extends ActiveRecord implements \yii\web\IdentityInterface{
    
    //根据主键返回对象
    public static function findIdentity($id)
    {
        return self::find()->where(['status'=>1,'id'=>$id])->one();
    }
    
    //api应用中使用较多,web应用一般不需要写函数体
    public static function findIdentityByAccessToken($token, $type = null)
    {
        // TODO: Implement findIdentityByAccessToken() method.
    }

    
    //返回主键信息
    public function getId()
    {
        return $this->id;
    }
    
    //以下两个方法下文会重点讲述到
    public function getAuthKey()
    {
        return $this->auth_key;
    }

    public function validateAuthKey($authKey)
    {
        return $this->auth_key===$authKey;
    }

    
    //这个钩子函数是用来生成auth_key的,注意在数据表中建立一个auth_key字段
    public function beforeSave($insert)
    {
        if(parent::beforeSave($insert)){
            if($this->isNewRecord){
                $this->auth_key=\Yii::$app->security->generateRandomString();
            }
            return true;
        }
        return false;
    }

}
//web.php配置文件中加入如下组件 
'user' => [
    //实现IdentityInterface接口的模型类
    'identityClass' => 'app\models\User',
    //开启自动登录,配合记住我功能使用
    'enableAutoLogin' => true,
    //设置登录地址,使用场景例如在ACF授权的使用如发现用户未登录会跳转到配置的登录地址
    'loginUrl'=>['login/login']
],

2.完成了第一步之后我们就可以使用user组件来管理我们的认证状态,以下是一些常见的操作:

//首先进行用户名和密码的合法性校验,之后执行如下语句,保存登录状态
 \Yii::$app->user->login($user,(bool)$this->remember_me?\Yii::$app->params['session_expire_time']:0);

//$this->remember_me当用户选择记住我时,这个值会true,session_expire_time是我自己配置的记住我的有效时间
//用户退出登录时,需要销毁登录状态
\Yii::$app->user->logout()
//介绍几个常用的user组件的属性
\Yii::$app->user->identity 当前用户的身份实例,未认证的用户则为null
\Yii::$app->user->id  当前用户的id,未认证的用户则为null
\Yii::$app->user->isGuest 判断当前用户是否是游客,用户未登录返回true

3.接下来我们来讲解auth_key的用途:我在刚接触user组件的时候也对auth_key感到困惑,查阅了一些资料之后发现,auth_key只有在使用cookie登录时才会使用到。跟踪login函数你会发现一个叫做switchIdentity的函数,查看它的函数体在最后你会发现一句代码:

//如果设置了自动登录并且有效期大于0则执行sendIdentityCookie
//$duration的值就是login函数的第二个参数
if ($this->enableAutoLogin && $duration > 0) {
    $this->sendIdentityCookie($identity, $duration);
}

接着我们查看sendIdentityCookie函数的实现:

protected function sendIdentityCookie($identity, $duration)
{
    $cookie = Yii::createObject(array_merge($this->identityCookie, [
        'class' => 'yii\web\Cookie',
        'value' => json_encode([
            $identity->getId(),
            $identity->getAuthKey(),
            $duration,
         ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
            'expire' => time() + $duration,
    ]));
    Yii::$app->getResponse()->getCookies()->add($cookie);
}

我们查看sendIdentityCookie的实现可以发现,当用户选择记住我时,会写入一个cookie,它的值是getId(),getAuthKey()以及有效期。因此猜测auth_key的用途应该是保证cookie更加安全吧。

4.我们找到了getAuthKey在哪里调用,那么有小伙伴肯定会问了validateAuthKey在哪里调用呢?我们可以在user组件的源代码中找到一个叫做loginByCookie的函数,其中调用了一个叫做getIdentityAndDurationFromCookie的函数,以下是这个函数的实现:

protected function getIdentityAndDurationFromCookie()
    {
        $value = Yii::$app->getRequest()->getCookies()->getValue($this->identityCookie['name']);
        if ($value === null) {
            return null;
        }
        $data = json_decode($value, true);

        //上一步我们知道了cookie中保存了三个值,所以才有了以下的if语句
        if (is_array($data) && count($data) == 3) {
            list($id, $authKey, $duration) = $data;
            /* @var $class IdentityInterface */
            $class = $this->identityClass;
            $identity = $class::findIdentity($id);
            if ($identity !== null) {
                if (!$identity instanceof IdentityInterface) {
                    throw new InvalidValueException("$class::findIdentity() must return an object implementing IdentityInterface.");

                //这里它调用了validateAuthKey来验证cookie中的auth_key是否正确
                } elseif (!$identity->validateAuthKey($authKey)) {
                    Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__);
                } else {
                    return ['identity' => $identity, 'duration' => $duration];
                }
            }
        }
        $this->removeIdentityCookie();
        return null;
    }

5.以上我们就简单介绍完了user组件的使用,并着重讲解了auth_key的作用(让cookie值更加安全)以及什么时候会使用到auth_key,接下来我分享一下使用user组件的经验:

查看user组件的源码你可以发现cookie的键默认是_identity,session中存的用户id默认的键是__id

 public $identityCookie = ['name' => '_identity', 'httpOnly' => true];
 public $idParam = '__id';

我们的web站一般都是有前后端的,那么如何前后端分离使用user组件呢?

//可以在组件中额外定义一个admin,class指定为yii\web\User即可
'admin'=>[
    'class'=>'yii\web\User',
    'identityClass'=>'app\modules\admin\models\Admin',
    'enableAutoLogin'=>true,
    'idParam'=>'__admin_id',
    'identityCookie'=>['name' => '_admin_identity', 'httpOnly' => true],
    'loginUrl'=>['admin/login/login']
],
'user' => [
    'identityClass' => 'app\models\User',
    'enableAutoLogin' => true,
    'loginUrl'=>['login/login']
],

由于我们前后端都使用了user组件,为了防止前端后端的cookie和session互相覆盖,所以在admin中重新指定属性idParam和identityCookie的值。

以上就是全部啦,感谢读到最后呀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值