Detailed Explanation of Login Exit and Automatic Login Function in Yii2 Framework

  • 2021-08-10 07:12:51
  • OfStack

In this paper, an example of Yii2 framework to achieve login, exit and automatic login functions. Share it for your reference, as follows:

The principle of automatic login is very simple. It is mainly realized by cookie

On the first login, if the login is successful and the next automatic login is selected, the user's authentication information will be saved in cookie, and the validity period of cookie is 1 year or several months.

When logging in next time, whether the user information is stored in cookie is judged first, if so, the user information stored in cookie is used to log in,

Configuring User Components

First, set the user component in the components of the configuration file


'user' => [
 'identityClass' => 'app\models\User',
 'enableAutoLogin' => true,
],

We see that enableAutoLogin is used to judge whether to enable the automatic login function, which has nothing to do with the next automatic login on the interface.

Only when enableAutoLogin is true, if the next automatic login is selected, the user information will be stored in cookie and the validity period of cookie will be set to 3600*24*30 seconds for the next login

Now let's look at how it is implemented in Yii.

1. Save cookie for the first login

1. login login function


public function login($identity, $duration = 0)
{
  if ($this->beforeLogin($identity, false, $duration)) {
   $this->switchIdentity($identity, $duration);
   $id = $identity->getId();
   $ip = Yii::$app->getRequest()->getUserIP();
   Yii::info("User '$id' logged in from $ip with duration $duration.", __METHOD__);
   $this->afterLogin($identity, false, $duration);
  }
  return !$this->getIsGuest();
}

In this case, you simply log in and then execute the switchIdentity method to set the authentication information.

2. switchIdentity sets authentication information


public function switchIdentity($identity, $duration = 0)
{
  $session = Yii::$app->getSession();
  if (!YII_ENV_TEST) {
   $session->regenerateID(true);
  }
  $this->setIdentity($identity);
  $session->remove($this->idParam);
  $session->remove($this->authTimeoutParam);
  if ($identity instanceof IdentityInterface) {
   $session->set($this->idParam, $identity->getId());
   if ($this->authTimeout !== null) {
    $session->set($this->authTimeoutParam, time() + $this->authTimeout);
   }
   if ($duration > 0 && $this->enableAutoLogin) {
    $this->sendIdentityCookie($identity, $duration);
   }
  } elseif ($this->enableAutoLogin) {
   Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
  }
}

This method is important, and it needs to be called when exiting.

This method has three main functions

① Set the validity period of session

If the validity period of cookie is greater than 0 and automatic login is allowed, the user's authentication information is saved in cookie

③ If automatic login is allowed, delete cookie information. This is called when exiting. The $identity passed in when exiting is null


protected function sendIdentityCookie($identity, $duration)
{
  $cookie = new Cookie($this->identityCookie);
  $cookie->value = json_encode([
   $identity->getId(),
   $identity->getAuthKey(),
   $duration,
  ]);
  $cookie->expire = time() + $duration;
  Yii::$app->getResponse()->getCookies()->add($cookie);
}

The user information stored in cookie contains three values:

$identity->getId()
$identity->getAuthKey()
$duration

getId () and getAuthKey () are in the IdentityInterface interface. We also know that when setting up User components, this User Model must implement IdentityInterface interface. Therefore, the first two values can be obtained in User Model, and the third value is the validity period of cookie.

2. Automatically log in from cookie

From the above, we know that the user's authentication information has been stored in cookie, so the next time we take the information directly from cookie and set it up.

1. AccessControl User Access Control

Yii provides AccessControl to judge whether the user logs in or not. With this, there is no need to judge again in every action


public function behaviors()
{
  return [
   'access' => [
    'class' => AccessControl::className(),
    'only' => ['logout'],
    'rules' => [
     [
      'actions' => ['logout'],
      'allow' => true,
      'roles' => ['@'],
     ],
    ],
   ],
  ];
}

2. getIsGuest and getIdentity judge whether to authenticate the user

isGuest is the most important attribute in the automatic login process.

In the above AccessControl access control, it judges whether it is an authenticated user through IsGuest attribute, and then calls getIdentity to obtain user information in getIsGuest method. If it is not empty, it means it is an authenticated user, otherwise it is a tourist (not logged in).


public function getIsGuest($checkSession = true)
{
  return $this->getIdentity($checkSession) === null;
}
public function getIdentity($checkSession = true)
{
  if ($this->_identity === false) {
   if ($checkSession) {
    $this->renewAuthStatus();
   } else {
    return null;
   }
  }
  return $this->_identity;
}

3. renewAuthStatus regenerates user authentication information


protected function renewAuthStatus()
{
  $session = Yii::$app->getSession();
  $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;
  if ($id === null) {
   $identity = null;
  } else {
   /** @var IdentityInterface $class */
   $class = $this->identityClass;
   $identity = $class::findIdentity($id);
  }
  $this->setIdentity($identity);
  if ($this->authTimeout !== null && $identity !== null) {
   $expire = $session->get($this->authTimeoutParam);
   if ($expire !== null && $expire < time()) {
    $this->logout(false);
   } else {
    $session->set($this->authTimeoutParam, time() + $this->authTimeout);
   }
  }
  if ($this->enableAutoLogin) {
   if ($this->getIsGuest()) {
    $this->loginByCookie();
   } elseif ($this->autoRenewCookie) {
    $this->renewIdentityCookie();
   }
  }
}

In this part, the user is judged by session first, because the user already exists in session after logging in. Then, if it is judged that it is automatic login, it is logged in through cookie information.

4. Log in to loginByCookie through the saved Cookie information


protected function loginByCookie()
{
  $name = $this->identityCookie['name'];
  $value = Yii::$app->getRequest()->getCookies()->getValue($name);
  if ($value !== null) {
   $data = json_decode($value, true);
   if (count($data) === 3 && isset($data[0], $data[1], $data[2])) {
    list ($id, $authKey, $duration) = $data;
    /** @var IdentityInterface $class */
    $class = $this->identityClass;
    $identity = $class::findIdentity($id);
    if ($identity !== null && $identity->validateAuthKey($authKey)) {
     if ($this->beforeLogin($identity, true, $duration)) {
      $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
      $ip = Yii::$app->getRequest()->getUserIP();
      Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__);
      $this->afterLogin($identity, true, $duration);
     }
    } elseif ($identity !== null) {
     Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__);
    }
   }
  }
}

Read the cookie value first, and then $data = json_decode($value, true); Deserialized into an array.

From the above code, you can know that in order to realize automatic login, all three values must have values. In addition, findIdentity and validateAuthKey must be implemented in User Model.

After the login is completed, you can reset the validity period of cookie, so that it can be valid for 1 time.


$this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);

3. Exit logout


public function logout($destroySession = true)
{
  $identity = $this->getIdentity();
  if ($identity !== null && $this->beforeLogout($identity)) {
   $this->switchIdentity(null);
   $id = $identity->getId();
   $ip = Yii::$app->getRequest()->getUserIP();
   Yii::info("User '$id' logged out from $ip.", __METHOD__);
   if ($destroySession) {
    Yii::$app->getSession()->destroy();
   }
   $this->afterLogout($identity);
  }
  return $this->getIsGuest();
}
public function switchIdentity($identity, $duration = 0)
{
  $session = Yii::$app->getSession();
  if (!YII_ENV_TEST) {
   $session->regenerateID(true);
  }
  $this->setIdentity($identity);
  $session->remove($this->idParam);
  $session->remove($this->authTimeoutParam);
  if ($identity instanceof IdentityInterface) {
   $session->set($this->idParam, $identity->getId());
   if ($this->authTimeout !== null) {
    $session->set($this->authTimeoutParam, time() + $this->authTimeout);
   }
   if ($duration > 0 && $this->enableAutoLogin) {
    $this->sendIdentityCookie($identity, $duration);
   }
  } elseif ($this->enableAutoLogin) {
   Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
  }
}

When you exit, set the current authentication to null first, and then judge if it is an automatic login function, then delete the relevant cookie information.

For more readers interested in Yii related contents, please check the topics on this site: "Introduction to Yii Framework and Summary of Common Skills", "Summary of Excellent Development Framework of php", "Introduction to smarty Template", "Introduction to php Object-Oriented Programming", "Summary of Usage of php String (string)", "Introduction to php+mysql Database Operation" and "Summary of Common Database Operation Skills of php"

I hope this article is helpful to the PHP programming based on Yii framework.


Related articles: