利用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 相关文章推荐
基于mysql的bbs设计(二)
Oct 09 PHP
PHP中cookies使用指南
Mar 16 PHP
php输出表格的实现代码(修正版)
Dec 29 PHP
php生成图形(Libchart)实例
Nov 06 PHP
解决PhpMyAdmin中导入2M以上大文件限制的方法分享
Jun 06 PHP
php获取网页上所有链接的方法
Apr 03 PHP
PHP基于工厂模式实现的计算器实例
Jul 16 PHP
php自动提交表单的方法(基于fsockopen与curl)
May 09 PHP
Ajax和PHP正则表达式验证表单及验证码
Sep 24 PHP
PHP数字前补0的自带函数sprintf 和number_format的用法(详解)
Feb 06 PHP
php简单生成一组与多组随机字符串的方法
May 09 PHP
php 中phar包的使用教程详解
Oct 26 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
使用php实现快钱支付功能(涉及到接口)
2013/07/01 PHP
什么是OneThink oneThink后台添加插件步骤
2016/04/13 PHP
URL编码转换,escape() encodeURI() encodeURIComponent()
2006/12/27 Javascript
form中限制文本字节数js代码
2007/06/10 Javascript
javascript 计算两个整数的百分比值
2009/12/26 Javascript
jQuery回车实现登录简单实现
2013/08/20 Javascript
jquery 循环显示div的示例代码
2013/10/18 Javascript
基于jQuery实现的向下滑动二级菜单效果代码
2015/08/31 Javascript
JS实现黑色风格的网页TAB选项卡效果代码
2015/10/09 Javascript
理解Javascript的call、apply
2015/12/16 Javascript
javascript动态添加checkbox复选框的方法
2015/12/23 Javascript
用window.onerror捕获并上报Js错误的方法
2016/01/27 Javascript
jQuery实现用户信息表格的添加和删除功能
2017/09/12 jQuery
JS实现的全排列组合算法示例
2017/10/09 Javascript
JS实现div模块的截图并下载功能
2017/10/17 Javascript
详解基于vue-cli配置移动端自适应
2018/01/13 Javascript
Vue表单及表单绑定方法
2018/09/04 Javascript
vue elementUI使用tabs与导航栏联动
2019/06/21 Javascript
javascript实现简单打字游戏
2019/10/29 Javascript
vue解决花括号数据绑定不成功的问题
2019/10/30 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
2020/08/03 Javascript
在Vue里如何把网页的数据导出到Excel的方法
2020/09/30 Javascript
[18:32]DOTA2 HEROS教学视频教你分分钟做大人-谜团
2014/06/12 DOTA
python实现在sqlite动态创建表的方法
2015/05/08 Python
django ajax json的实例代码
2018/05/29 Python
pandas将numpy数组写入到csv的实例
2018/07/04 Python
从pandas一个单元格的字符串中提取字符串方式
2019/12/17 Python
Django --Xadmin 判断登录者身份实例
2020/07/03 Python
Java方面的关于数组和继承的笔面试题
2015/09/18 面试题
STP协议的主要用途是什么?为什么要用STP
2012/12/20 面试题
教导处工作制度
2014/01/18 职场文书
2014年商场超市庆元旦活动方案
2014/02/14 职场文书
公司董事长岗位职责
2014/06/08 职场文书
创先争优个人承诺书
2014/08/30 职场文书
广播体操比赛主持词
2015/06/29 职场文书
Django实现WebSocket在线聊天室功能(channels库)
2021/09/25 Python