laravel 5 中的登录事件处理

login event handling in laravel 5

我什至在我的 L5 应用程序中尝试挂钩登录以设置上次登录时间和 IP 地址。我可以让它与以下内容一起使用:

Event::listen('auth.login', function($event)
{
    Auth::user()->last_login = new DateTime;
    Auth::user()->last_login_ip = Request::getClientIp();
    Auth::user()->save();
});

但是,我想知道在 L5 中执行此操作的最佳方法是使用事件处理程序对象。我尝试创建一个事件处理程序并在事件服务提供程序中添加 auth.login 作为数组键,但这没有用。我不确定 auth.login 事件是否可行。如果不是,那么放上面代码最合适的地方在哪里。为了测试,我把它放在我的 routes.php 文件中,但我知道它不应该放在那里。

请小心询问 做 X 的最佳方法是什么,因为 Laravel 尤其提供了完成同一任务的多种方法 -- 有些是在某些情况下比其他人更好。

看看 Laravel documentation,我个人会选择 "Basic Usage",因为它似乎与您陈述的用例相匹配。

如果我们 运行 下面的 Artisan 命令,我们可以为 UserLoggedIn 事件生成一个模板。

$ php artisan make:event UserLoggedIn

(注意过去时态,因为事件发生了,然后订阅者会收到事件发生的通知)

(注意 2:命名空间中的 app 字符串是 Laravel 开箱即用的,如果您执行了 php artisan app:name 命令,它可能与您不同)

下面的class是为我们生成的:

<?php namespace app\Events;

use app\Events\Event;

use Illuminate\Queue\SerializesModels;

class UserLoggedIn extends Event {

    use SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

}

如果我们在构造函数中添加一个 userId 参数,那么事件就不需要知道 Auth Facade/Guard 合约。这意味着我们的 UserLoggedIn 事件代码并未与 Eloquent 或您决定在您的应用程序中使用的任何身份验证框架紧密耦合。无论如何,让我们添加 userId 参数。

<?php namespace app\Events;

use app\Events\Event;
use app\User;

use Illuminate\Queue\SerializesModels;

class UserLoggedIn extends Event {

    use SerializesModels;

    public $userId;

    /**
     * Create a new event instance.
     *
     * @param int userId the primary key of the user who was just authenticated.
     *
     * @return void
     */
    public function __construct($userId)
    {
        $this->userId = $userId;
    }

}

现在您可能想知道,这很好,但是我们如何处理这个事件?好问题!我们需要创建一个事件处理程序来处理此事件何时被触发。让我们现在使用 Artisan 来做到这一点:

$ php artisan handler:event UpdateUserMetaData --event=UserLoggedIn

我们将新的事件处理程序命名为 UpdateUserMetaData 并告诉 Artisan 我们要处理的事件是 UserLoggedIn 事件。

现在我们在 app/Handlers/Events/UpdateUserMetaData.php:

中有一些看起来像这样的代码
<?php namespace app\Handlers\Events;

use app\Events\UserLoggedIn;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;

class UpdateUserMetaData {

    /**
     * Create the event handler.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  UserLoggedIn  $event
     * @return void
     */
    public function handle(UserLoggedIn $event)
    {
        //
    }

}

我们可以更新 handle 方法,以便能够像上面指定的那样很容易地处理此事件:

<?php namespace app\Handlers\Events;

use app\Events\UserLoggedIn;

use Illuminate\Http\Request;

class UpdateUserMetaData {

    protected $request;

    /**
     * Create the event handler.
     *
     * @param Request $request
     */
    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    /**
     * Handle the event.
     *
     * @param  UserLoggedIn  $event
     */
    public function handle(UserLoggedIn $event)
    {
        $user = User::find($event->userId); // find the user associated with this event
        $user->last_login = new DateTime;
        $user->last_login_ip = $this->request->getClientIp();
        $user->save();
    }

}

附带说明一下,如果您不熟悉 Carbon, you might want to look into using it so you can take advantage of its fantastic API like you can with Eloquent's created_at and updated_at timestamp fields on most models. Here's a link for how to tell Eloquent which fields should be used with Carbon: http://laravel.com/docs/master/eloquent#date-mutators

在此代码将在您的 Laravel 应用程序中运行之前,我们必须执行最后两个步骤。

  1. 我们需要将事件映射到app/Providers目录下的EventServiceProviderclass中的事件处理器

  2. 我们需要在登录后触发事件。

要完成第一步,我们只需要将我们的事件 class 添加到 app/Providers/EventServiceProvder.php 中的 $listeners 属性,如下所示:

    UserLoggedIn::class => [
        UpdateUserMetaData::class
    ]

如果您在 EventServiceProvider class 中导入 classes 并且您使用的是 PHP 5.5,以上内容将有效。如果您使用的是较低的 PHP 版本,您需要提供每个 class 的完整路径作为字符串,如下所示:'app/Events/UserLoggedIn''app/Handlers/Events/UpdateUserMetaData'.

$listeners 数组将事件映射到它们各自的处理程序。

好的,现在是最后一步了!在你的代码库中,找到用户认证的地方,添加如下内容:

event(new \app\Events\UserLoggedIn(Auth::user()->id));

大功告成!我在写这个答案时测试了这段代码,如果您有任何后续问题,请随时提出。

打开 EventServiceProvider.php 并在引导方法中您可以通过回调监听 'auth.login' 事件。

public function boot(DispatcherContract $events)
{
    parent::boot($events);
    $events->listen('auth.login', function() 
    {
        dd('logged in event');
    });
}

您可能想要创建侦听器,以便将回调函数移至其他位置。按照 http://laravel.com/docs/4.2/events#using-classes-as-listeners

执行此操作

编辑:这仅适用于 5.0.* 和 5.1.*.

对于 5.2.* 解决方案,请参阅下面的 JuLiAnc 回复。

在处理了两个建议的答案并进行了更多研究之后,我终于想出了如何按照我最初尝试的方式来做到这一点。

i 运行 以下 artisan 命令

$ php artisan handler:event AuthLoginEventHandler

然后我更改了生成的 class,删除了事件 class 的导入,并导入了用户模型。我还将 User $user$remember 传递给 handle 方法,因为当触发 auth.login 事件时,这就是传递的内容。

<?php namespace App\Handlers\Events;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use App\User;

class AuthLoginEventHandler {

    /**
     * Create the event handler.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  User $user
     * @param  $remember
     * @return void
     */
    public function handle(User $user, $remember)
    {
        dd("login fired and handled by class with User instance and remember variable");
    }

}

现在我打开 EventServiceProvided.php 并修改 $listen 数组如下:

protected $listen = [
    'auth.login' => [
        'App\Handlers\Events\AuthLoginEventHandler',
    ],
];

我意识到如果一开始这不起作用,您可能需要

$ php artisan clear-compiled

我们开始了!我们现在可以使用事件处理程序 class!

响应通过 auth.login 事件登录的用户

就是这样做的

    <?php

namespace App\Providers;

use App\User;
use Auth;
use DB;


use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [

    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        $events->listen('auth.login', function() 
        {

            DB::table('users')
                -> where('id', Auth::id())
                -> update(array(
                        'last_login'    => date('Y-m-d H:i:s')
                    ));

        });

        //
    }
}

在laravel 5.2; auth.login 不起作用...必须使用以下内容:

protected $listen = [
    'Illuminate\Auth\Events\Attempting' => [
        'App\Listeners\LogAuthenticationAttempt',
    ],

    'Illuminate\Auth\Events\Login' => [
        'App\Listeners\LogSuccessfulLogin',
    ],

    'Illuminate\Auth\Events\Logout' => [
        'App\Listeners\LogSuccessfulLogout',
    ],

    'Illuminate\Auth\Events\Lockout' => [
        'App\Listeners\LogLockout',
    ],
];

如文档中所述here

对于 5.2 类似这样

在听众中:

use Carbon\Carbon;
use Illuminate\Auth\Events\Login;

class UpdateLastLoginWithIp
{
    public function handle(Login $event)
    {
        $event->user->last_login_at = Carbon::now();
        $event->user->last_login_ip = Request::getClientIp()
        $event->user->save();
    }
}

在EventServiceProvider.php中:

protected $listen = [
        'Illuminate\Auth\Events\Login' => [
            'City\Listeners\UpdateLastLoginWithIp',
        ],
    ];

这是我的方法:
当用户登录时,我已经完成了制作事件处理程序的工作:

  • Laravel 5.8

1) 运行 下面的 artian 命令
php artisan make:listener Auth/UserLoggedIn --event='Illuminate\Auth\Events\Login'*

它将在文件夹 app\Listeners\Auth\

中创建一个监听器:UserLoggedIn

2) 然后你需要将这个监听器添加到你的 EventServiceProvider:**

...
protected $listen = [
   ...
        'Illuminate\Auth\Events\Login' => [
            'App\Listeners\Auth\UserLoggedIn',
        ],
    ];

当用户登录位于 UserLoggedIn 侦听器:

handle 函数时,您终于可以进行登录了
public function handle(Login $event)
    {
        //you have access to user object by using : $event->user
    }
  • 您可以使用所有其他 Auth 事件,以下是可能的事件:
'Illuminate\Auth\Events\Registered', 
'Illuminate\Auth\Events\Attempting', 
'Illuminate\Auth\Events\Authenticated', 
'Illuminate\Auth\Events\Login', 
'Illuminate\Auth\Events\Failed',
'Illuminate\Auth\Events\Logout',
'Illuminate\Auth\Events\Lockout',

**您可以在 EventServiceProvider 中使用所有这些事件: https://laravel.com/docs/5.8/authentication#events

一般用户登录日志可以这样一步步实现

首先,你应该有 Auth Scaffolding

  1. 将其用作事件,
    • 'Illuminate\Auth\Events\Login' 登录事件
    • 'Illuminate\Auth\Events\Logout' 注销事件

将登录和注销事件定位在:

vendor\laravel\framework\src\Illuminate\Auth\Events

EventServiceProvider.php

protected $listen = [

    'Illuminate\Auth\Events\Login' => [
        'App\Listeners\LoginLogs',
    ],

    'Illuminate\Auth\Events\Logout' => [
        'App\Listeners\LogoutLogs',
    ],

];


public function boot()
{
    parent::boot();

}
  1. 然后在完成 EventServiceProvider 之后,执行下一步
    • 键入此 artisan 命令 php artisan event:generate
    • 在 App 文件夹中查找文件夹 Listener,检查是否包含 php 文件 LoginLogs注销日志
  2. 创建您的 迁移模型

命令: php artisan make:migration create_UserLoginHistory

迁移文件

public function up()
{
    Schema::create('tbl_user_login_history', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->integer('user_id');
        $table->datetime('login_at')->nullable();
        $table->datetime('logout_at')->nullable();
        $table->string('login_ip')->nullable();
        $table->string('role');
        $table->string('session_id');
        $table->timestamps();
    });
}


public function down()
{
    Schema::dropIfExists('tbl_user_login_history');
}

那么你的模型UserLoginHistory

public $timestamps = false;

protected $table = 'tbl_user_login_history';

protected $fillable = ['user_id','login_at','logout_at','login_ip','role','session_id'];

public function setLogOutLog(){

    $this->where('session_id',request()->session()->getId())->update([
        'logout_at' =>Carbon::now(),
        ]);

}

public function setLogInLog(){
    $this->insert(
        ['user_id' => Auth::user()->id,'login_at' =>Carbon::now(),
        'login_ip'=>request()->getClientIp(),'role' =>Auth::user()->role,
        'session_id'=>request()->session()->getId()
        ]);  
}

4.after 迁移和模型创建过程,假设您已经在用户 table

中担任角色
  1. 听众部分

侦听器登录日志 Class

use App\UserLoginHistory;


private $UserLoginHistory; 

public function __construct(UserLoginHistory $UserLoginHistory)
{
  // the initialization of  private $UserLoginHistory; 

    $this->UserLoginHistory = $UserLoginHistory;
}


public function handle(Login $event)
{   
     // from model UserLoginHistory

     $this->UserLoginHistory->setLogInLog();
}

侦听器注销日志 Class

private $UserLogoutHistory; 

public function __construct(UserLoginHistory $UserLoginHistory)
{
    // the initialization of  private $UserLogoutHistory; 

    $this->UserLogoutHistory = $UserLoginHistory;
}


public function handle(Logout $event)
{
    // from model UserLoginHistory
     $this->UserLogoutHistory->setLogOutLog();
}

完成所有步骤后,尝试使用 Auth

登录