YII2登录

以YII2自带的登录代码为例

//这是控制器的登录动作
if (!Yii::$app->user->isGuest) {
            return $this->goHome();
        }
        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post()) && $model->login()) {
            return $this->goBack();
        }
        return $this->render('login', [
            'model' => $model,
        ]);

以上依次调用了load和login方法,load方法为验证数据的合法性还有用户的密码

public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // rememberMe must be a boolean value
            ['rememberMe', 'boolean'],
            // password is validated by validatePassword()
            ['password', 'validatePassword'],  //这里调用了validatePassword方法去验证密码
        ];
    }

public function validatePassword($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();

            if (!$user || !$user->validatePassword($this->password)) {
                $this->addError($attribute, 'Incorrect username or password.');
            }
        }
    }

第二个login登录方法如下:

//这里是LoginForm模型类
public function login()
    {
        if ($this->validate()) {
            //这里对login传进了用户实例和rememberMe标识
            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
        }
        return false;
    }

其中传入getUser()和以rememberMe标识传入时间,getUser()方法则是返回用户表的实例:

public function getUser()
    {
        if ($this->_user === false) {
            $this->_user = UserExt::findByUsername($this->username);
        }

        return $this->_user;
    }

然后又继续调用YII的user组件的login方法进行登录:

public function login(IdentityInterface $identity, $duration = 0)
    {
        if ($this->beforeLogin($identity, false, $duration)) {
            //这里进行主要的登录逻辑
            $this->switchIdentity($identity, $duration);
            $id = $identity->getId();
            $ip = Yii::$app->getRequest()->getUserIP();
            if ($this->enableSession) {
                $log = "User '$id' logged in from $ip with duration $duration.";
            } else {
                $log = "User '$id' logged in from $ip. Session not enabled.";
            }
            Yii::info($log, __METHOD__);
            $this->afterLogin($identity, false, $duration);
        }

        return !$this->getIsGuest();
    }

其中switchIdentity方法就是处理登录以及登出的逻辑,相关的方法如下:

public function switchIdentity($identity, $duration = 0)
    {
        $this->setIdentity($identity);

        if (!$this->enableSession) {
            return;
        }

        /* Ensure any existing identity cookies are removed. */
        if ($this->enableAutoLogin && ($this->autoRenewCookie || $identity === null)) {
            $this->removeIdentityCookie();
        }

        $session = Yii::$app->getSession();
        if (!YII_ENV_TEST) {
            $session->regenerateID(true);
        }
        $session->remove($this->idParam);
        $session->remove($this->authTimeoutParam);

        if ($identity) {
            $session->set($this->idParam, $identity->getId());
            if ($this->authTimeout !== null) {
                $session->set($this->authTimeoutParam, time() + $this->authTimeout);
            }
            if ($this->absoluteAuthTimeout !== null) {
                $session->set($this->absoluteAuthTimeoutParam, time() + $this->absoluteAuthTimeout);
            }
            //这里则根据是否开启了自动登录(在配置文件配置)以及上面传的rememberMe参数判断是否进行自动登录
            if ($this->enableAutoLogin && $duration > 0) {
                $this->sendIdentityCookie($identity, $duration);
            }
        }
    }

主要是清除之前存在的cookie再把新的用户实例写进cookie,如果rememberMe为true的前提下还会调用sendIdentityCookie方法发送有失效期的cookie:

protected function sendIdentityCookie($identity, $duration)
    {
        //解析Cookie
        $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,
        ]));
        //发送Cookie
        Yii::$app->getResponse()->getCookies()->add($cookie);
    }

这里就要求需要自行实现用户模型的getId和getAuthKey方法,这就是主要的登录行为的逻辑。

主动登录

如果在登录的时候提交了rememberMe参数,就会触发自动登录的行为,实现这个行为的方法在Yii的User组件里:

protected function loginByCookie()
    {
        $data = $this->getIdentityAndDurationFromCookie();
        if (isset($data['identity'], $data['duration'])) {
            $identity = $data['identity'];
            $duration = $data['duration'];
            if ($this->beforeLogin($identity, true, $duration)) {
                //根据用户实例进行登录操作
                $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
                $id = $identity->getId();
                $ip = Yii::$app->getRequest()->getUserIP();
                Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__);
                $this->afterLogin($identity, true, $duration);
            }
        }
    }

protected function getIdentityAndDurationFromCookie()
    {
        //获取cookie并进行解析
        $value = Yii::$app->getRequest()->getCookies()->getValue($this->identityCookie['name']);
        if ($value === null) {
            return null;
        }
        $data = json_decode($value, true);
        //对cookie进行验证,成功则返回用户实例,失败则清空cookie
        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.");
                } 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;
    }

在getIdentityAndDurationFromCookie方法中的$data则为存在客户端的cookie数据

array(3) { [0]=> int(1) [1]=> string(32) "i2bbB1bIga_PGehlATvu-p1UrDuW5Lw7" [2]=> int(2592000) } 

然后便是对cookie数据进行了验证并完成登录,验证的需要实现用户实例的findIdentity和validateAuthKey方法。

这里说明一下,用户实例是根据用户表模型自行创建的模型类,而User组件则是yii\web\user。对应的指南在这。

你可能感兴趣的:(YII2登录)