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 相关文章推荐
mysql建立外键
Nov 25 PHP
linux实现php定时执行cron任务详解
Dec 24 PHP
php反射应用示例
Feb 25 PHP
php支持中文字符串分割的函数
May 28 PHP
weiphp微信公众平台授权设置
Jan 04 PHP
PHP使用socket发送HTTP请求的方法
Feb 14 PHP
PHP简单实现文本计数器的方法
Apr 28 PHP
基于PHP实现数据分页显示功能
May 26 PHP
PHP MYSQL简易交互式站点开发
Dec 27 PHP
Laravel框架使用Redis的方法详解
May 30 PHP
php和vue配合使用技巧和方法
May 09 PHP
Yii 框架使用数据库(databases)的方法示例
May 19 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 5.6版本中编写一个PHP扩展的简单示例
2015/01/20 PHP
crontab无法执行php的解决方法
2016/01/25 PHP
PHP实现自动发送邮件功能代码(qq 邮箱)
2017/08/18 PHP
php生成微信红包数组的方法
2019/09/05 PHP
JavaScript执行顺序详细介绍
2013/12/04 Javascript
Jquery中ajax方法data参数的用法小结
2014/02/12 Javascript
使用JavaScript获取电池状态的方法
2014/05/03 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
JavaScript性能优化之小知识总结
2015/11/20 Javascript
JavaScript使ifram跨域相互访问及与PHP通信的实例
2016/03/03 Javascript
原生js获取元素样式的简单方法
2016/08/06 Javascript
jQuery事件用法详解
2016/10/06 Javascript
js实现html table 行,列锁定的简单实例
2016/10/13 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
Vue filters过滤器的使用方法
2017/07/14 Javascript
AngularJS路由删除#符号解决的办法
2017/09/28 Javascript
vue组件中使用iframe元素的示例代码
2017/12/13 Javascript
详解在vue-cli中使用graphql即vue-apollo的用法
2018/09/08 Javascript
Vue中CSS动画原理的实现
2019/02/13 Javascript
react写一个select组件的实现代码
2019/04/03 Javascript
ant design vue 表格table 默认勾选几项的操作
2020/10/31 Javascript
Python QQBot库的QQ聊天机器人
2019/06/19 Python
Python 实现日志同时输出到屏幕和文件
2020/02/19 Python
微信端html5页面调用分享接口示例
2018/03/14 HTML / CSS
html5中使用hotcss.js实现手机端自适配的方法
2020/04/23 HTML / CSS
C语言笔试集
2012/07/24 面试题
星空联盟C# .net笔试题
2014/12/05 面试题
工程采购员岗位职责
2014/03/09 职场文书
机关单位动员会主持词
2014/03/20 职场文书
安全生产承诺书范文
2014/05/22 职场文书
公司运动会策划方案
2014/05/25 职场文书
青春励志演讲稿范文
2014/08/25 职场文书
党员活动总结
2015/02/04 职场文书
2015年社区居委会工作总结
2015/05/18 职场文书
Python+uiautomator2实现自动刷抖音视频功能
2021/04/29 Python
opencv 分类白天与夜景视频的方法
2021/06/05 Python