利用Laravel事件系统如何实现登录日志的记录详解


Posted in PHP onMay 20, 2017

本文介绍的是利用Laravel事件系统实现登录日志记录的相关内容,分享出来给大家参考,下面来看看详细的介绍:

明确需求

记录一个登录日志,通常需要下列信息:

  • 客户端Agent信息
  • 客户端IP地址
  • 访问IP地点
  • 登录时间
  • 登录用户信息

确立工具

明确完需求后,根据每个需求查找自己所需的工具吧。

  • 需求1 jenssegers/agent就可以满足我们要求
  • 需求2 Laravel下直接Request::getClientIp()
  • 需求3 zhuzhichao/ip-location-zh这个包可以满足要求
  • 需求4 time()
  • 需求5 登录用户模型

开工

采用Laravel的事件订阅系统来实现,需要实现一个登录事件和一个登录事件监听器。

生成事件和监听器

Laravel命令行支持自动生成事件和监听器,在App\Providers\EventServiceProvider中添加需要实现的事件:

protected $listen = [ 
  ...,
  //添加登录事件及对应监听器,一个事件可绑定多个监听器
  'App\Events\LoginEvent' => [
  'App\Listeners\LoginListener',
 ],
];

运行命令:php artisan event:generate就会自动生成事件和监听器,已存在的事件和监听器不会发生改变。

登录事件(Event)

回顾下需求,我们的登录事件需要的5点信息,在事件中需要记录这些信息,所以事件设计如下:

namespace App\Events;

use Illuminate\Broadcasting\Channel; 
use Illuminate\Queue\SerializesModels; 
use Illuminate\Broadcasting\PrivateChannel; 
use Illuminate\Foundation\Events\Dispatchable; 
use Illuminate\Broadcasting\InteractsWithSockets;

use App\Models\User; 
use Jenssegers\Agent\Agent;

class LoginEvent 
{
 use Dispatchable, InteractsWithSockets, SerializesModels;

 /**
 * @var User 用户模型
 */
 protected $user;

 /**
 * @var Agent Agent对象
 */
 protected $agent;

 /**
 * @var string IP地址
 */
 protected $ip;

 /**
 * @var int 登录时间戳
 */
 protected $timestamp;

 /**
 * 实例化事件时传递这些信息
 */
 public function __construct($user, $agent, $ip, $timestamp)
 {
 $this->user = $user;
 $this->agent = $agent;
 $this->ip = $ip;
 $this->timestamp = $timestamp;
 }

 public function getUser()
 {
 return $this->user;
 }

 public function getAgent()
 {
 return $this->agent;
 }

 public function getIp()
 {
 return $this->ip;
 }

 public function getTimestamp()
 {
 return $this->timestamp;
 }

 /**
 * Get the channels the event should broadcast on.
 *
 * @return Channel|array
 */
 public function broadcastOn()
 {
 return new PrivateChannel('channel-default');
 }
}

在事件中记录所需要的信息,并实现这些信息的get方法。

登录监听器(Listener)

在监听器中,获取到事件传递过来的信息,把这些信息记录到数据库中,实现如下:

namespace App\Listeners;

use App\Events\LoginEvent;

class LoginListener 
{

 // handle方法中处理事件
 public function handle(LoginEvent $event)
 {
 //获取事件中保存的信息
 $user = $event->getUser();
 $agent = $event->getAgent();
 $ip = $event->getIp();
 $timestamp = $event->getTimestamp();

 //登录信息
 $login_info = [
  'ip' => $ip,
  'login_time' => $timestamp,
  'user_id' => $user->id
 ];

 // zhuzhichao/ip-location-zh 包含的方法获取ip地理位置
 $addresses = \Ip::find($ip);
 $login_info['address'] = implode(' ', $addresses);

 // jenssegers/agent 的方法来提取agent信息
 $login_info['device'] = $agent->device(); //设备名称
 $browser = $agent->browser();  
 $login_info['browser'] = $browser . ' ' . $agent->version($browser); //浏览器
 $platform = $agent->platform();
 $login_info['platform'] = $platform . ' ' . $agent->version($platform); //操作系统
 $login_info['language'] = implode(',', $agent->languages()); //语言
 //设备类型
 if ($agent->isTablet()) {
  // 平板
  $login_info['device_type'] = 'tablet';
 } else if ($agent->isMobile()) {
  // 便捷设备
  $login_info['device_type'] = 'mobile';
 } else if ($agent->isRobot()) {
  // 爬虫机器人
  $login_info['device_type'] = 'robot';
  $login_info['device'] = $agent->robot(); //机器人名称
 } else {
  // 桌面设备
  $login_info['device_type'] = 'desktop';
 }

 //插入到数据库
 DB::table('login_log')->insert($login_info);

 } 
}

这样,监听器就完成了,每次一触发登录事件,就会在数据库中添加一条登录信息。

触发事件

通过全局的event()方法来触发事件,event()方法的参数为事件实例:

namespace App\Controllers; 
...
use App\Events\LoginEvent; 
use Jenssegers\Agent\Agent; 
class AuthControoler extends Controller 
{
 ...
 public function login(Request $request)
 {
 //登录实现
 ...
 //登录成功,触发事件
 event(new LoginEvent($this->guard()->user(), new Agent(), \Request::getClientIp(), time()));
 ... 
 } 
}

队列化监听器

有时监听器会进行一些耗时操作,这时应该结合Laravel的队列系统将监听器进行队列化,前提是已经配置了队列并开启了队列处理器。

队列化非常简单,只需监听器实现ShouldQueue接口即可,即:

namespace App\Listeners; 
...
use Illuminate\Contracts\Queue\ShouldQueue; 
class LoginListener implements ShouldQueue 
{
 /**
 * 失败重试次数
 * @var int
 */
 public $tries = 1;
 ...
}

总结

Laravel的事件系统实现起来还是非常优雅的,同一个事件可以很方便的添加各类监听器,且各个监听器之间互不干扰,解耦性非常强。加上队列系统,可以很方便的处理一些后续任务。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
asp和php下textarea提交大量数据发生丢失的解决方法
Jan 20 PHP
PHP 日志缩略名的创建函数代码
May 26 PHP
php 高性能书写
Dec 11 PHP
php教程之phpize使用方法
Feb 12 PHP
PHP中比较两个字符串找出第一个不同字符位置例子
Apr 08 PHP
PHP中比较时间大小实例
Aug 21 PHP
IIS下PHP的三种配置方式对比
Nov 20 PHP
PHP+AJAX实现投票功能的方法
Sep 28 PHP
深入理解PHP内核(二)之SAPI探究
Nov 10 PHP
PHP实现转盘抽奖算法分享
Apr 15 PHP
在thinkphp5.0路径中实现去除index.php的方式
Oct 16 PHP
php 函数中静态变量使用的问题实例分析
Mar 05 PHP
Yii框架实现图片上传的方法详解
May 20 #PHP
Yii框架分页实现方法详解
May 20 #PHP
thinkPHP显示不出验证码的原因与解决方法分析
May 20 #PHP
yii2项目实战之restful api授权验证详解
May 20 #PHP
ThinkPHP下表单令牌错误与解决方法分析
May 20 #PHP
PHP那些琐碎的知识点(整理)
May 20 #PHP
PHP使用xpath解析XML的方法详解
May 20 #PHP
You might like
超外差式晶体管收音机的组装与统调
2021/03/01 无线电
php 正则表达式小结
2009/08/31 PHP
PHP定时任务延缓执行的实现
2014/10/08 PHP
php清除和销毁session的方法分析
2015/03/19 PHP
php实现上传图片文件代码
2015/07/19 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
jquery实现的超出屏幕时把固定层变为定位层的代码
2010/02/23 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
2012/12/26 Javascript
JavaScript在for循环中绑定事件解决事件参数不同的情况
2014/01/20 Javascript
js中文逗号转英文实现
2014/02/11 Javascript
JQuery1.8 判断元素是否绑定事件的方法
2014/07/10 Javascript
原生javascript实现隔行换色
2015/01/04 Javascript
javascript制作幻灯片(360度全景图片)
2015/07/28 Javascript
Node.js文件操作方法汇总
2016/03/22 Javascript
JS生成和下载二维码的代码
2016/12/07 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
2017/02/20 Javascript
微信小程序 action-sheet 反馈上拉菜单简单实例
2017/05/11 Javascript
详解webpack进阶之loader篇
2017/08/23 Javascript
使用JavaScript保存文本文件到本地的两种方法
2019/01/22 Javascript
Vue-CLI 3.X 部署项目至生产服务器的方法
2019/03/22 Javascript
mui js控制开关状态、修改switch开关的值方法
2019/09/03 Javascript
浅谈JS中几种轻松处理'this'指向方式
2019/09/16 Javascript
JavaScript中的this/call/apply/bind的使用及区别
2020/03/06 Javascript
Vant Weapp组件踩坑:picker的初始赋值解决
2020/11/12 Javascript
vue3.0+vue-router+element-plus初实践
2020/12/02 Vue.js
[01:08:10]2014 DOTA2国际邀请赛中国区预选赛 SPD-GAMING VS LGD-CDEC
2014/05/22 DOTA
[05:17]DOTA2誓师:今天我们在这里 明天TI4等我!
2014/03/26 DOTA
python图像处理之反色实现方法
2015/05/30 Python
美体小铺法国官方网站:The Body Shop法国
2020/06/04 全球购物
Yahoo-PHP面试题4
2012/05/05 面试题
自荐信怎么写呢?
2013/12/09 职场文书
第二课堂活动总结
2014/05/07 职场文书
好听的队名和口号
2014/06/09 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
2015年师德师风承诺书
2015/01/22 职场文书
MATLAB 全景图切割及盒图显示的实现步骤
2021/05/14 Python