Yii2框架实现登录、退出及自动登录功能的方法详解


Posted in PHP onOctober 24, 2017

本文实例讲述了Yii2框架实现登录、退出及自动登录功能的方法。分享给大家供大家参考,具体如下:

自动登录的原理很简单。主要就是利用cookie来实现的

在第一次登录的时候,如果登录成功并且选中了下次自动登录,那么就会把用户的认证信息保存到cookie中,cookie的有效期为1年或者几个月。

在下次登录的时候先判断cookie中是否存储了用户的信息,如果有则用cookie中存储的用户信息来登录,

配置User组件

首先在配置文件的components中设置user组件

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

我们看到enableAutoLogin就是用来判断是否要启用自动登录功能,这个和界面上的下次自动登录无关。

只有在enableAutoLogin为true的情况下,如果选择了下次自动登录,那么就会把用户信息存储起来放到cookie中并设置cookie的有效期为3600*24*30秒,以用于下次登录

现在我们来看看Yii中是怎样实现的。

一、第一次登录存cookie

1、login 登录功能

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

在这里,就是简单的登录,然后执行switchIdentity方法,设置认证信息。

2、switchIdentity设置认证信息

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

这个方法比较重要,在退出的时候也需要调用这个方法。

这个方法主要有三个功能

① 设置session的有效期

② 如果cookie的有效期大于0并且允许自动登录,那么就把用户的认证信息保存到cookie中

③ 如果允许自动登录,删除cookie信息。这个是用于退出的时候调用的。退出的时候传递进来的$identity为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);
}

存储在cookie中的用户信息包含有三个值:

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

getId()和getAuthKey()是在IdentityInterface接口中的。我们也知道在设置User组件的时候,这个User Model是必须要实现IdentityInterface接口的。所以,可以在User Model中得到前两个值,第三值就是cookie的有效期。

二、自动从cookie登录

从上面我们知道用户的认证信息已经存储到cookie中了,那么下次的时候直接从cookie里面取信息然后设置就可以了。

1、AccessControl用户访问控制

Yii提供了AccessControl来判断用户是否登录,有了这个就不需要在每一个action里面再判断了

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

2、getIsGuest、getIdentity判断是否认证用户

isGuest是自动登录过程中最重要的属性。

在上面的AccessControl访问控制里面通过IsGuest属性来判断是否是认证用户,然后在getIsGuest方法里面是调用getIdentity来获取用户信息,如果不为空就说明是认证用户,否则就是游客(未登录)。

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 重新生成用户认证信息

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

这一部分先通过session来判断用户,因为用户登录后就已经存在于session中了。然后再判断如果是自动登录,那么就通过cookie信息来登录。

4、通过保存的Cookie信息来登录 loginByCookie

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

先读取cookie值,然后$data = json_decode($value, true);反序列化为数组。

这个从上面的代码可以知道要想实现自动登录,这三个值都必须有值。另外,在User Model中还必须要实现findIdentityvalidateAuthKey这两个方法。

登录完成后,还可以再重新设置cookie的有效期,这样便能一起有效下去了。

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

三、退出 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));
  }
}

退出的时候先把当前的认证设置为null,然后再判断如果是自动登录功能则再删除相关的cookie信息。

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
PHP 程序员也要学会使用“异常”
Jun 16 PHP
nginx+php-fpm配置文件的组织结构介绍
Nov 07 PHP
LotusPhp笔记之:Logger组件的使用方法
May 06 PHP
php防止SQL注入详解及防范
Nov 12 PHP
php中mysql连接和基本操作代码(快速测试使用,简单方便)
Apr 25 PHP
ThinkPHP跳转页success及error模板实例教程
Jul 17 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
Aug 06 PHP
php利用反射实现插件机制的方法
Mar 14 PHP
PHP框架Laravel插件Pagination实现自定义分页
Apr 22 PHP
Django 中 cookie的使用
Aug 17 PHP
使用laravel和ajax实现整个页面无刷新的操作方法
Oct 03 PHP
PHP随机生成中文段落示例【测试网站内容时使用】
Apr 26 PHP
Yii2.0实现生成二维码功能实例
Oct 24 #PHP
完美的php分页类
Oct 24 #PHP
PHP设计模式之工厂模式详解
Oct 24 #PHP
2017年最好用的9个php开发工具推荐(超好用)
Oct 23 #PHP
thinkPHP5实现的查询数据库并返回json数据实例
Oct 23 #PHP
php实现的后台表格分页功能示例
Oct 23 #PHP
php双层循环(九九乘法表)
Oct 23 #PHP
You might like
日本十大科幻动漫 宇宙骑士垫底,第一已成经典
2020/03/04 日漫
PHP 自定义错误处理函数trigger_error()
2013/03/26 PHP
PHP中array_merge和array相加的区别分析
2013/06/17 PHP
php中count获取多维数组长度的方法
2014/11/03 PHP
php将csv文件导入到mysql数据库的方法
2014/12/24 PHP
php支付宝在线支付接口开发教程
2016/09/19 PHP
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
javascript中定义类的方法汇总
2014/12/28 Javascript
jquery实现简单实用的弹出层效果代码
2015/10/15 Javascript
jQuery插件ajaxfileupload.js实现上传文件
2020/10/23 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
JQuery获得内容和属性方法解析
2020/05/30 jQuery
如何搭建一个完整的Vue3.0+ts的项目步骤
2020/10/18 Javascript
详解Python设计模式编程中观察者模式与策略模式的运用
2016/03/02 Python
Python用zip函数同时遍历多个迭代器示例详解
2016/11/14 Python
Python导入模块时遇到的错误分析
2017/08/30 Python
Python中如何导入类示例详解
2019/04/17 Python
python 猴子补丁(monkey patch)
2019/06/26 Python
Python3实现zip分卷压缩过程解析
2019/10/09 Python
python使用paramiko实现ssh的功能详解
2020/03/06 Python
pycharm 激活码及使用方式的详细教程
2020/05/12 Python
python源文件的字符编码知识点详解
2021/03/04 Python
html5中localStorage本地存储的简单使用
2017/06/16 HTML / CSS
分享一个H5原生form表单的checkbox特效代码
2018/02/26 HTML / CSS
HTML5 常用语法一览(列举不支持的属性)
2010/01/26 HTML / CSS
英国领先的瓷砖专家:Walls and Floors
2018/04/27 全球购物
eDreams葡萄牙:全球最大的在线旅行社之一
2019/04/15 全球购物
大学生实习期自我评价范文
2013/10/03 职场文书
关于幼儿的自我评价
2013/12/18 职场文书
社保代办委托书怎么写
2014/10/06 职场文书
工程承包协议书
2014/10/20 职场文书
申论不会写怎么办?教您掌握这6点思维和原则
2019/07/17 职场文书
2019年教师节活动策划方案
2019/09/09 职场文书
利用Python将list列表写入文件并读取的方法汇总
2022/03/25 Python
i5-10400f处理相当于i7多少水平
2022/04/19 数码科技
zabbix如何添加监控主机和自定义监控项
2022/08/14 Servers