php Laravel 5 中的登录事件处理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28970105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:10:55  来源:igfitidea点击:

login event handling in laravel 5

phplaravellaravel-5

提问by Erik

i am trying to hook to the login even in my L5 app to set last login time and IP address. i can make it work with the following:

即使在我的 L5 应用程序中,我也试图登录以设置上次登录时间和 IP 地址。我可以使用以下方法使其工作:

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

however, i am wondering what the best way to do this in L5 is with the event handler object. i tried creating an event handler and adding auth.login as an array key in the events service provider, however that didnt work. im not sure if that is possible or not with the auth.login event. if it isnt, where is the most appropriate place to put the above code. for testing, i put it in my routes.php file, but i know that isnt where it should be.

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

回答by JuLiAnc

In laravel 5.2; auth.login won't work... the following will have to be used:

在 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',
    ],
];

As stated in the documentation here

如文档中说明这里

回答by Erik

EDIT: this only works in 5.0.* and 5.1.*.

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

For the 5.2.* solution see JuLiAnc response below.

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

after working with both proposed answers, and some more research i finally figured out how to do this the way i was trying at first.

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

i ran the following artisan command

我运行了以下工匠命令

$ php artisan handler:event AuthLoginEventHandler

Then i altered the generated class removing the import of the Event class and and imported the user model. I also passed User $userand $rememberto the handle method since when the auth.login event is fired, thats what is passed.

然后我更改了生成的类,删除了 Event 类的导入,并导入了用户模型。我还传递了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");
    }

}

now i opened EventServiceProvided.php and modified the $listenarray as follows:

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

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

i realized if this doesn't work at first, you may need to

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

$ php artisan clear-compiled

There we go! we can now respond to the user logging in via the auth.login event using an event handler class!

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

回答by kstev

Be careful about asking what the best way to do Xis, because Laravel, in particular, provides many ways of accomplishing the same task -- some are better than others in certain situations.

在询问执行 X 的最佳方法时要小心,因为 Laravel 尤其提供了许多完成相同任务的方法——在某些情况下,有些方法比其他方法更好。

Taking a look at the Laravel documentation, personally I would go with the "Basic Usage" as it seems to match the use case you have stated.

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

If we run the following Artisan command we can generate a template for the UserLoggedIn event.

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

$ php artisan make:event UserLoggedIn

(note the past tense, because events happen, and thenthe subscribers are notified of the event having taken place)

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

(note 2: the appstring in namespaces is what Laravel uses out of the box, it is likely different for you if you have executed the php artisan app:namecommand)

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

The following class is generated for us:

为我们生成了以下类:

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

}

If we add a userIdparameter to the constructor, then the event doesn't need to know about the Auth Facade/Guard Contract. This means our UserLoggedInevent code is not tightly coupled to Eloquent or which ever authentication framework you decide to utilize in your app. Anyways, let's add that userIdparameter.

如果我们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;
    }

}

Now you're probably wondering, well that's great and all, but how to we act on this event? Great question! We need to create an event handler to handle when this event is fired. Let's do that now using Artisan:

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

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

We name our new event handler UpdateUserMetaDataand tell Artisan that the event we want to handle is the UserLoggedInevent.

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

Now we have some code that looks like this inside of app/Handlers/Events/UpdateUserMetaData.php:

现在我们有一些看起来像这样的代码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)
    {
        //
    }

}

We can update the handle method to be able to handle this event like you specified above quite easily:

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

}

As a side note, if you're not familiar with 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_atand updated_attimestamp 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.

附带说明一下,如果您不熟悉Carbon,您可能想考虑使用它,以便您可以像在大多数模型上使用 Eloquentcreated_atupdated_at时间戳字段一样利用其出色的 API 。这是如何告诉 Eloquent 哪些字段应该与 Carbon 一起使用的链接:http: //laravel.com/docs/master/eloquent#date-mutators

There are two final steps we have to perform before this code will work in your Laravel app.

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

  1. We need to map the event to the event handler in the EventServiceProviderclass under the app/Providersdirectory.

  2. We need to fire the event after login.

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

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

To complete the first step, we just need to add our event classes to the $listenersproperty in app/Providers/EventServiceProvder.phplike so:

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

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

The above will work provided you import the classes inside the EventServiceProviderclass, and you are using PHP 5.5. If you're using a lower PHP version, you'll need to provide the full path to each class as a string like this: 'app/Events/UserLoggedIn'and 'app/Handlers/Events/UpdateUserMetaData'.

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

The $listenersarray maps events to their respective handlers.

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

Okay, now for the final step! In your code base, find the place where the user is authenticated and add the following:

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

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

And we're done! I tested this code as I wrote this answer, feel free to ask follow up questions if you have any.

我们完成了!我在编写此答案时测试了此代码,如果您有任何后续问题,请随时提出后续问题。

回答by goldie

For 5.2 something like this

对于 5.2 这样的东西

in Listeners:

在听众中:

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();
    }
}

In EventServiceProvider.php :

在 EventServiceProvider.php 中:

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

回答by Alphas Bravos

Usually you can achieve by doing like this step by step for User Login Logs

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

first, you should have Auth Scaffolding

首先,你应该有 Auth Scaffolding

  1. use this as event,
    • 'Illuminate\Auth\Events\Login'for Login Event
    • 'Illuminate\Auth\Events\Logout'for Logout Event
  1. 将此用作事件,
    • 'Illuminate\Auth\Events\Login'用于登录事件
    • 'Illuminate\Auth\Events\Logout'用于注销事件

located the login and logout event at :

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

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

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

EventServiceProvider.php

事件服务提供者.php

protected $listen = [

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

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

];


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

}
  1. then after you get done for EventServiceProvider, do this next step
    • type this artisan command php artisan event:generate
    • look for folder Listenerinside App folder, check if contains php files both LoginLogsand LogoutLogs
  2. create your migrationand model
  1. 然后在完成 EventServiceProvider 后,执行下一步
    • 输入这个工匠命令php artisan event:generate
    • 在 App 文件夹中查找文件夹Listener,检查是否包含LoginLogsLogoutLogs 的php 文件
  2. 创建您的迁移模型

command:php artisan make:migration create_UserLoginHistory

命令:php artisan make:migration create_UserLoginHistory

Migration File

迁移文件

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');
}

then your Model: UserLoginHistory

那么你的模型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 the migration and model creation procedure, let's assume that you have already in roles in users table

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

  1. the listener part
  1. 听者部分

Listener: LoginLogsClass

侦听器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();
}

Listener: LogoutLogsClass

侦听器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();
}

after you do this all steps , try to login with Auth

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

回答by Ramin

here is my approach:
I have done for making an event handler when user logged in using:

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

  • Laravel 5.8
  • Laravel 5.8

1) Run the following artian command
php artisan make:listener Auth/UserLoggedIn --event='Illuminate\Auth\Events\Login'*

It will make a Listener: UserLoggedInin folder app\Listeners\Auth\

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

它将创建一个 Listener:UserLoggedIn在文件夹中app\Listeners\Auth\

2) Then you need to add this listener into your EventServiceProvider:**

2)然后您需要将此侦听器添加到您的EventServiceProvider:**

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

Finaly you can do log when user logged in in handlefunction located at UserLoggedInListener:

最后,当用户登录handle位于UserLoggedInListener 的函数时,您可以进行登录:

public function handle(Login $event)
    {
        //you have access to user object by using : $event->user
    }
  • you can use all other Auth events, here is the possible events:
  • 您可以使用所有其他 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',

**You can use all these events in your EventServiceProvider: https://laravel.com/docs/5.8/authentication#events

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

回答by Kyslik

Open up EventServiceProvider.php and in boot method you can listen for 'auth.login'event via callback.

打开 EventServiceProvider.php 并在 boot 方法中'auth.login'通过回调监听事件。

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

You may want to create listener so you move callback function somewhere else. Do that following this http://laravel.com/docs/4.2/events#using-classes-as-listeners

您可能想要创建侦听器,以便将回调函数移到其他地方。按照http://laravel.com/docs/4.2/events#using-classes-as-listeners执行此操作

回答by juergen

just did it this way

就是这样做的

    <?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')
                    ));

        });

        //
    }
}