Yii2的登录超时问题

参考文章:Yii 2.0学习日记:用户登陆详细解析(上)Yii 2.0学习日记:用户登陆详细解析(下)


结论:

1. user组件的配置控制session超时时间;

2. Yii::$app->user->login()方法控制cookie超时时间;

3. 如果两个都超时,就需要重新登录了;

4. 代码示例:

// user组件:
'user' => [
    'identityClass' => 'common\models\system\User',
    'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
    'enableAutoLogin' => true,  // 启用基于 cookie 的登录
    'authTimeout' => 60,  // session 超时时间
],

// Yii::$app->user->login()方法:
Yii::$app->user->login($this->getUser(), 120);


我们直接看User::switchIdentity()方法,该方法设置登录用户的session和cookie:

public function switchIdentity($identity, $duration = 0)
{
    // 精简一部分...
  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);  // ③
    }
    if ($this->enableAutoLogin && $duration > 0) {
      $this->sendIdentityCookie($identity, $duration);  // ④
    }
  }
}

由①处代码,会设置一个session,将用户的id保存到session id为__id

由②处代码,当$authTimeout不为null时,设置一个超时时间,session id为__expire

由③处代码,当$absoluteAuthTimeout不为null时,设置一个绝对超时时间,session id为__absoluteExpire

由④处代码,当$enableAutoLogin = true并且$duration > 0时,设置一个cookie,以便session过期后,可以通过cookie自动登录;


问题1,怎么实现页面600秒无访问,就需要重新登录呢?

要实现这个功能,我们可以直接修改user组件:

'user' => [
    'identityClass' => 'common\models\User',
    'enableAutoLogin' => true,  // 启用基于cookie的登录
    'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
    'authTimeout' => 600,  // session超时时间
],

但是如果直接关闭浏览器,session会销毁,登录状态也会注销。


问题2,怎么实现页面600秒无访问(或者关闭浏览器),但是不超过1200秒再次访问,就不需要重新登录呢??

我们可以通过调用user::login()方法,来实现该功能($enableAutoLogin必须为true):

// common\models\LoginForm:
public function login()
{
    if ($this->validate()) {
        //return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
        return Yii::$app->user->login($this->getUser(), 1200);
    }
    return false;
}

意思就是,只要cookie还没有失效(超过1200秒),我们就可以通过cookie来直接登录用户,而不需要重新输入用户名密码。



Yii2 的自动登录:

protected function renewAuthStatus()
{
    $session = Yii::$app->getSession();
    $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;

    if ($id === null) {
        $identity = null;
    } else {
        /* @var $class IdentityInterface */
        $class = $this->identityClass;
        $identity = $class::findIdentity($id);
    }

    $this->setIdentity($identity);

    if ($identity !== null && ($this->authTimeout !== null || $this->absoluteAuthTimeout !== null)) {
        $expire = $this->authTimeout !== null ? $session->get($this->authTimeoutParam) : null;
        $expireAbsolute = $this->absoluteAuthTimeout !== null ? $session->get($this->absoluteAuthTimeoutParam) : null;
        if ($expire !== null && $expire < time() || $expireAbsolute !== null && $expireAbsolute < time()) {
            $this->logout(false);
        } elseif ($this->authTimeout !== null) {
            $session->set($this->authTimeoutParam, time() + $this->authTimeout);
        }
    }

    if ($this->enableAutoLogin) {
        if ($this->getIsGuest()) {
            $this->loginByCookie();
        } elseif ($this->autoRenewCookie) {
            $this->renewIdentityCookie();
        }
    }
}

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

解析上面的代码:

首先,获取session中的用户id;

然后,根据用户id获取用户信息;

接着,判断session是否过期,未过期,则更新session;已过期,则注销用户。

再接着,如果启用了基于cookie的登录:

1、如果是来宾,则获取cookie信息,未过期则自动登录用户;

2、如果不是来宾,则更新cookie信息。