利用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 相关文章推荐
我的论坛源代码(七)
Oct 09 PHP
PHP mb_convert_encoding 获取字符串编码类型实现代码
Apr 26 PHP
php 连接mssql数据库 初学php笔记
Mar 01 PHP
php 上传文件类型判断函数(避免上传漏洞 )
Jun 08 PHP
设置php页面编码的两种方法示例介绍
Mar 03 PHP
基于GD2图形库的PHP生成图片缩略图类代码分享
Feb 08 PHP
Session 失效的原因汇总及解决丢失办法
Sep 30 PHP
php读取出一个文件夹及其子文件夹下所有文件的方法示例
Jun 15 PHP
PHP7新特性之抽象语法树(AST)带来的变化详解
Jul 17 PHP
CI框架附属类用法分析
Dec 26 PHP
PHP设计模式之数据访问对象模式(DAO)原理与用法实例分析
Dec 12 PHP
PhpStorm连接服务器并实现自动上传功能
Dec 09 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
Smarty安装配置方法
2008/04/10 PHP
php实现搜索类封装示例
2016/03/31 PHP
PHP异步进程助手async-helper
2018/02/05 PHP
PHP使用PhpSpreadsheet操作Excel实例详解
2020/03/26 PHP
PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)
2020/08/03 PHP
JS 用6N±1法求素数 实例教程
2009/10/20 Javascript
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
2010/12/08 Javascript
jquery中选择块并改变属性值的方法
2013/07/31 Javascript
JSP防止网页刷新重复提交数据的几种方法
2016/11/19 Javascript
AngularJS实现的简单拖拽功能示例
2018/01/02 Javascript
Vue中computed与methods的区别详解
2018/03/24 Javascript
让IDE识别webpack的别名alias的实现方法
2020/05/06 Javascript
[01:38]DOTA2第二届亚洲邀请赛中国区预选赛出线战队晋级之路
2017/01/17 DOTA
[51:17]完美世界DOTA2联赛循环赛Inki vs DeMonsTer 第二场 10月30日
2020/10/31 DOTA
python笔记(1) 关于我们应不应该继续学习python
2012/10/24 Python
python抓取京东商城手机列表url实例代码
2013/12/18 Python
Python编写生成验证码的脚本的教程
2015/05/04 Python
jupyter notebook 使用过程中python莫名崩溃的原因及解决方式
2020/04/10 Python
Python实现进度条和时间预估的示例代码
2020/06/02 Python
用python获取txt文件中关键字的数量
2020/12/24 Python
Python Selenium操作Cookie的实例方法
2021/02/28 Python
CSS3新增布局之: flex详解
2020/06/18 HTML / CSS
命名空间(namespace)和程序集(Assembly)有什么区别
2015/09/25 面试题
上海天奕面试题笔试题
2015/04/19 面试题
西安当代医院管理研究院笔试题
2015/12/11 面试题
Shell如何接收变量输入
2016/08/06 面试题
Linux文件系统类型
2012/02/15 面试题
有abstract方法的类一定要用abstract修饰吗
2016/03/14 面试题
运动会入场词60字
2014/02/15 职场文书
买卖协议书范本
2014/04/21 职场文书
教师考核评语大全
2014/12/31 职场文书
公司给客户的感谢信
2015/01/23 职场文书
python生成可执行exe控制Microsip自动填写号码并拨打功能
2021/06/21 Python
mybatis3中@SelectProvider传递参数方式
2021/08/04 Java/Android
如何利用 CSS Overview 面板重构优化你的网站
2021/10/24 HTML / CSS
正则表达式基础与常用验证表达式
2022/06/16 Javascript