利用Laravel事件系统如何实现登录日志的记录详解
本文介绍的是利用Laravel事件系统实现登录日志记录的相关内容,分享出来给大家参考,下面来看看详细的介绍:
明确需求
记录一个登录日志,通常需要下列信息:
- 客户端Agent信息
- 客户端IP地址
- 访问IP地点
- 登录时间
- 登录用户信息
确立工具
明确完需求后,根据每个需求查找自己所需的工具吧。
- 需求1jenssegers/agent就可以满足我们要求
- 需求2Laravel下直接Request::getClientIp()
- 需求3zhuzhichao/ip-location-zh这个包可以满足要求
- 需求4time()
- 需求5登录用户模型
开工
采用Laravel的事件订阅系统来实现,需要实现一个登录事件和一个登录事件监听器。
生成事件和监听器
Laravel命令行支持自动生成事件和监听器,在App\Providers\EventServiceProvider中添加需要实现的事件:
protected$listen=[ ..., //添加登录事件及对应监听器,一个事件可绑定多个监听器 'App\Events\LoginEvent'=>[ 'App\Listeners\LoginListener', ], ];
运行命令:phpartisanevent:generate就会自动生成事件和监听器,已存在的事件和监听器不会发生改变。
登录事件(Event)
回顾下需求,我们的登录事件需要的5点信息,在事件中需要记录这些信息,所以事件设计如下:
namespaceApp\Events; useIlluminate\Broadcasting\Channel; useIlluminate\Queue\SerializesModels; useIlluminate\Broadcasting\PrivateChannel; useIlluminate\Foundation\Events\Dispatchable; useIlluminate\Broadcasting\InteractsWithSockets; useApp\Models\User; useJenssegers\Agent\Agent; classLoginEvent { useDispatchable,InteractsWithSockets,SerializesModels; /** *@varUser用户模型 */ protected$user; /** *@varAgentAgent对象 */ protected$agent; /** *@varstringIP地址 */ protected$ip; /** *@varint登录时间戳 */ protected$timestamp; /** *实例化事件时传递这些信息 */ publicfunction__construct($user,$agent,$ip,$timestamp) { $this->user=$user; $this->agent=$agent; $this->ip=$ip; $this->timestamp=$timestamp; } publicfunctiongetUser() { return$this->user; } publicfunctiongetAgent() { return$this->agent; } publicfunctiongetIp() { return$this->ip; } publicfunctiongetTimestamp() { return$this->timestamp; } /** *Getthechannelstheeventshouldbroadcaston. * *@returnChannel|array */ publicfunctionbroadcastOn() { returnnewPrivateChannel('channel-default'); } }
在事件中记录所需要的信息,并实现这些信息的get方法。
登录监听器(Listener)
在监听器中,获取到事件传递过来的信息,把这些信息记录到数据库中,实现如下:
namespaceApp\Listeners; useApp\Events\LoginEvent; classLoginListener { //handle方法中处理事件 publicfunctionhandle(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'; }elseif($agent->isMobile()){ //便捷设备 $login_info['device_type']='mobile'; }elseif($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()方法的参数为事件实例:
namespaceApp\Controllers; ... useApp\Events\LoginEvent; useJenssegers\Agent\Agent; classAuthControolerextendsController { ... publicfunctionlogin(Request$request) { //登录实现 ... //登录成功,触发事件 event(newLoginEvent($this->guard()->user(),newAgent(),\Request::getClientIp(),time())); ... } }
队列化监听器
有时监听器会进行一些耗时操作,这时应该结合Laravel的队列系统将监听器进行队列化,前提是已经配置了队列并开启了队列处理器。
队列化非常简单,只需监听器实现ShouldQueue接口即可,即:
namespaceApp\Listeners; ... useIlluminate\Contracts\Queue\ShouldQueue; classLoginListenerimplementsShouldQueue { /** *失败重试次数 *@varint */ public$tries=1; ... }
总结
Laravel的事件系统实现起来还是非常优雅的,同一个事件可以很方便的添加各类监听器,且各个监听器之间互不干扰,解耦性非常强。加上队列系统,可以很方便的处理一些后续任务。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。