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来写记数器(详细介绍)
Oct 09 PHP
用PHP连接MySQL代码的参数说明
Jun 07 PHP
php session应用实例 登录验证
Mar 16 PHP
php ss7.5的数据调用 (笔记)
Mar 08 PHP
PHP中限制IP段访问、禁止IP提交表单的代码
Apr 23 PHP
PHP获取当前页面完整URL的实现代码
Jun 10 PHP
又一个PHP实现的冒泡排序算法分享
Aug 21 PHP
php不使用copy()函数复制文件的方法
Mar 13 PHP
php将字符串随机分割成不同长度数组的方法
Jun 01 PHP
深入理解PHP中的empty和isset函数
May 26 PHP
php封装的mongodb操作类代码
Aug 06 PHP
thinkphp5.0整合phpsocketio完整攻略(绕坑)
Oct 12 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
php查看session内容的函数
2008/08/27 PHP
php GUID生成函数和类
2014/03/10 PHP
解决更换PHP5.4以上版本后Dedecms后台登录空白问题的方法
2015/10/23 PHP
Laravel中注册Facades的步骤详解
2016/03/16 PHP
jquery 打开窗口返回值实现代码
2010/03/04 Javascript
JS字符串函数扩展代码
2011/09/13 Javascript
网页加载时页面显示进度条加载完成之后显示网页内容
2012/12/23 Javascript
火狐textarea输入法的bug的触发及解决
2013/07/24 Javascript
JQuery之focus函数使用介绍
2013/08/20 Javascript
控制input输入框中提示信息的显示和隐藏的方法
2014/02/12 Javascript
使用JavaScript开发IE浏览器本地插件实例
2015/02/18 Javascript
javascript实现很浪漫的气泡冒出特效
2020/09/05 Javascript
javascript基础知识
2016/06/07 Javascript
JS实现简单的选择题测评系统代码思路详解(demo)
2017/09/03 Javascript
React实践之Tree组件的使用方法
2017/09/30 Javascript
开发一个Parcel-vue脚手架工具(详细步骤)
2018/09/22 Javascript
推荐一个基于Node.js的表单验证库
2019/02/15 Javascript
JavaScript实现获取两个排序数组的中位数算法示例
2019/02/26 Javascript
layui+SSM的数据表的增删改实例(利用弹框添加、修改)
2019/09/27 Javascript
Python基于正则表达式实现检查文件内容的方法【文件检索】
2017/08/30 Python
python GUI库图形界面开发之PyQt5窗口控件QWidget详细使用方法
2020/02/26 Python
Python爬虫爬取电影票房数据及图表展示操作示例
2020/03/27 Python
keras 自定义loss损失函数,sample在loss上的加权和metric详解
2020/05/23 Python
使用OpenCV获取图像某点的颜色值,并设置某点的颜色
2020/06/02 Python
在pycharm中debug 实时查看数据操作(交互式)
2020/06/09 Python
python中执行smtplib失败的处理方法
2020/07/01 Python
基于pycharm 项目和项目文件命名规则的介绍
2021/01/15 Python
StudentUniverse英国:学生航班、酒店和旅游
2019/08/25 全球购物
会计毕业生自荐信
2013/11/21 职场文书
挖掘机司机岗位职责
2014/02/12 职场文书
社团活动总结书
2014/06/27 职场文书
2014年医院个人工作总结
2014/12/09 职场文书
公务员政审材料
2014/12/23 职场文书
总经理致辞
2015/07/29 职场文书
python文件名批量重命名脚本实例代码
2021/04/22 Python
解决mysql模糊查询索引失效问题的几种方法
2021/06/18 MySQL