laravel 5中的登录事件处理

Eri*_*rik 12 php laravel 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();
});
Run Code Online (Sandbox Code Playgroud)

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

小智 22

在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',
    ],
];
Run Code Online (Sandbox Code Playgroud)

如文档中说明这里


Eri*_*rik 19

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

对于5.2.*解决方案,请参阅下面的JuLiAnc响应.

在完成了两个建议的答案之后,还有一些研究我最终想出了如何以我最初尝试的方式做到这一点.

我运行了以下工匠命令

$ php artisan handler:event AuthLoginEventHandler
Run Code Online (Sandbox Code Playgroud)

然后我改变了生成的类,删除了Event类的导入,并导入了用户模型.我也通过User $user$remember于当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");
    }

}
Run Code Online (Sandbox Code Playgroud)

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

protected $listen = [
    'auth.login' => [
        'App\Handlers\Events\AuthLoginEventHandler',
    ],
];
Run Code Online (Sandbox Code Playgroud)

我意识到如果这首先不起作用,你可能需要

$ php artisan clear-compiled
Run Code Online (Sandbox Code Playgroud)

我们去!我们现在可以使用事件处理程序类响应通过auth.login事件登录的用户!


kst*_*tev 15

小心询问X的最佳方式是什么,因为Laravel特别提供了许多方法来完成相同的任务 - 在某些情况下,有些方法比其他方法更好.

看一下Laravel文档,我个人会选择"基本用法",因为它似乎与您所说的用例相匹配.

如果我们运行以下Artisan命令,我们可以为UserLoggedIn事件生成模板.

$ php artisan make:event UserLoggedIn
Run Code Online (Sandbox Code Playgroud)

(注意过去时,因为事件发生,然后订阅者被告知发生了事件)

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

为我们生成以下类:

<?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()
    {
        //
    }

}
Run Code Online (Sandbox Code Playgroud)

如果我们userId向构造函数添加参数,那么事件不需要知道Auth Facade/Guard Contract.这意味着我们的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;
    }

}
Run Code Online (Sandbox Code Playgroud)

现在你可能想知道,这很好,但是我们如何采取行动呢?好问题!我们需要创建一个事件处理程序来处理触发此事件的时间.现在让我们使用Artisan做到这一点:

$ php artisan handler:event UpdateUserMetaData --event=UserLoggedIn
Run Code Online (Sandbox Code Playgroud)

我们命名我们的新事件处理程序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)
    {
        //
    }

}
Run Code Online (Sandbox Code Playgroud)

我们可以更新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();
    }

}
Run Code Online (Sandbox Code Playgroud)

作为旁注,如果您不熟悉Carbon,您可能需要考虑使用它,这样您就可以利用其出色的API,就像大多数模型中的Eloquent created_atupdated_at时间戳字段一样.以下是如何告诉Eloquent哪些字段应与Carbon一起使用的链接:http://laravel.com/docs/master/eloquent#date-mutators.

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

  1. 我们需要将事件映射到目录EventServiceProvider下的类中的事件处理程序app/Providers.

  2. 我们需要在登录后激活该事件.

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

    UserLoggedIn::class => [
        UpdateUserMetaData::class
    ]
Run Code Online (Sandbox Code Playgroud)

如果您在类中导入EventServiceProvider类,并且您使用的是PHP 5.5,则上述操作将起作用.如果你使用较低的PHP版本,你需要提供每个类的完整路径作为这样的字符串:'app/Events/UserLoggedIn''app/Handlers/Events/UpdateUserMetaData'.

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

好的,现在是最后一步!在您的代码库中,找到用户通过身份验证的位置并添加以下内容:

event(new \app\Events\UserLoggedIn(Auth::user()->id));
Run Code Online (Sandbox Code Playgroud)

我们完成了!我在编写这个答案时测试了这段代码,如果你有任何问题,请随时提出后续问题.

  • 不,几乎一样,但我发送了Eloquent模型.我知道你在关于在门口留下雄辩的事情是有道理的,但它的一个大泡沫请阅读:https://laracasts.com/forum/?p = 718-repository-pattern-and-eloquent-models/p1#p3546这就是为什么我不像疯了一样解耦.还有一点,通过发送user_id而不是模型,您需要运行一个以上的查询,我确信您已经运行它只需查看debugbar(包).我使用Eloquent ORM,所以我全职使用它.我可能会在存储库中抽象一些东西但不是一切. (2认同)
  • 我认为`php artisan event:generate`将生成类EventServiceProvider中列出的任何事件或处理程序 (2认同)

小智 12

对于像这样的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在EventServiceProvider.php中:

protected $listen = [
        'Illuminate\Auth\Events\Login' => [
            'City\Listeners\UpdateLastLoginWithIp',
        ],
    ];
Run Code Online (Sandbox Code Playgroud)


小智 6

通常您可以通过对用户登录日志执行此操作来逐步实现

首先,你应该有 Auth Scaffolding

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

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

供应商\laravel\framework\src\Illuminate\Auth\Events

事件服务提供者.php

protected $listen = [

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

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

];


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

}
Run Code Online (Sandbox Code Playgroud)
  1. 然后在完成 EventServiceProvider 之后,执行下一步
    • 输入这个工匠命令php artisan event:generate
    • 在 App 文件夹中查找文件夹Listener,检查是否包含LoginLogsLogoutLogs 的php 文件
  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');
}
Run Code Online (Sandbox Code Playgroud)

那么你的模型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()
        ]);  
}
Run Code Online (Sandbox Code Playgroud)

4.在迁移和模型创建过程之后,假设您已经在 users 表中的角色

  1. 听者部分

侦听器LoginLogs

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();
}
Run Code Online (Sandbox Code Playgroud)

侦听器LogoutLogs

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();
}
Run Code Online (Sandbox Code Playgroud)

完成所有步骤后,尝试使用身份验证登录