利用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 相关文章推荐
使用php4加速网络传输
Oct 09 PHP
php cache类代码(php数据缓存类)
Apr 15 PHP
php中数字0和空值的区别分析
Jun 05 PHP
windows8.1下Apache+Php+MySQL配置步骤
Oct 30 PHP
学习php设计模式 php实现原型模式(prototype)
Dec 07 PHP
详解 PHP加密解密字符串函数附源码下载
Dec 18 PHP
分享PHP计算两个日期相差天数的代码
Dec 23 PHP
PHP绕过open_basedir限制操作文件的方法
Jun 10 PHP
laravel5.2表单验证,并显示错误信息的实例
Sep 29 PHP
php操作redis数据库常见方法实例总结
Feb 20 PHP
浅析PHP中json_encode与json_decode的区别
Jul 15 PHP
PHP7 标准库修改
Mar 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
php 学习资料零碎东西
2010/12/04 PHP
PHP大转盘中奖概率算法实例
2014/10/21 PHP
编写PHP脚本使WordPress的主题支持Widget侧边栏
2015/12/14 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
jQuery Dialog 弹出层对话框插件
2010/08/09 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
jQuery插件bgStretcher.js实现全屏背景特效
2015/06/05 Javascript
Underscore源码分析
2015/12/30 Javascript
JavaScript中setTimeout和setInterval函数的传参及调用
2016/03/11 Javascript
值得分享的bootstrap table实例
2016/09/22 Javascript
Javascript+CSS3实现进度条效果
2016/10/28 Javascript
form+iframe解决跨域上传文件的方法
2016/11/18 Javascript
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
[01:10:02]IG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python 合并文件的具体实例
2013/08/08 Python
使用Python3制作TCP端口扫描器
2017/04/17 Python
Python进度条实时显示处理进度的示例代码
2018/01/30 Python
Python装饰器用法示例小结
2018/02/11 Python
对python中Librosa的mfcc步骤详解
2019/01/09 Python
python3实现绘制二维点图
2019/12/04 Python
python实现测试工具(一)——命令行发送get请求
2020/10/19 Python
Python项目实战之使用Django框架实现支付宝付款功能
2021/02/23 Python
python中random模块详解
2021/03/01 Python
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
欧洲顶级体育电子商务网站:SportsShoes.com
2018/03/27 全球购物
含精油的天然有机化妆品:Indemne
2019/08/27 全球购物
工程概预算专业毕业生求职信
2013/10/04 职场文书
电子信息专业学生自荐信
2013/11/09 职场文书
中学生爱国演讲稿
2013/12/31 职场文书
中学教师教育感言
2014/02/21 职场文书
高三化学教学反思
2016/02/22 职场文书
古诗之感恩老师
2019/10/24 职场文书
浅谈mysql执行过程以及顺序
2021/05/12 MySQL
如何理解及使用Python闭包
2021/06/01 Python
Python实现日志实时监测的示例详解
2022/04/06 Python
解决IDEA翻译插件Translation报错更新TTK失败不能使用
2022/04/24 Python