如何使用 laravel 5 中的队列通过电子邮件发送密码重置链接

Posted

技术标签:

【中文标题】如何使用 laravel 5 中的队列通过电子邮件发送密码重置链接【英文标题】:How to send the password reset link via email using queue in laravel 5 【发布时间】:2016-03-28 07:51:51 【问题描述】:

我正在使用 laravel 的 ResetsPasswords 特征来实现密码重置。我想要实现的是使用队列发送电子邮件。通过代码挖掘,我在函数 postEmail() 中找到了以下行:

$response = Password::sendResetLink($request->only('email'), function (Message $message) 
            $message->subject($this->getEmailSubject());
        ); 

进一步挖掘,我注意到 sendResetLink() 函数是在 PasswordBroker 类中实现的,该类又调用函数 emailResetLink()。 emailResetLink 函数返回以下内容:

return $this->mailer->send($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) 
            $m->to($user->getEmailForPasswordReset());

我可以简单地将mailer->send 更改为mailer->queue。在不修改这个非项目文件的情况下,他们有更好的方法吗?

【问题讨论】:

【参考方案1】:

这就是 Laravel 容器派上用场的地方。如果您不喜欢核心组件的功能,那么您可以轻松地覆盖它。

首先您需要创建自己的 PasswordBroker:

namespace App\Auth\Passwords;

use Illuminate\Auth\Passwords\PasswordBroker as IlluminatePasswordBroker;

class PasswordBroker extends IlluminatePasswordBroker


    public function emailResetLink()
    
        $view = $this->emailView;

        return $this->mailer->queue($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) 
            $m->to($user->getEmailForPasswordReset());
            if (! is_null($callback)) 
                call_user_func($callback, $m, $user, $token);
            
        );
    


如果您想将命名空间放在应用中的其他位置,请将其更改为您想要的任何名称。

由于注册服务的服务提供者是deferred service provider,您需要创建自己的提供者来替换它。可能最简单的方法是扩展Illuminate\Auth\Passwords\PasswordResetServiceProvider,如下所示:

namespace App\Providers;

use App\Auth\Passwords\PasswordBroker;

class PasswordResetServiceProvider extends \Illuminate\Auth\Passwords\PasswordResetServiceProvider


    protected function registerPasswordBroker()
    
        $this->app->singleton('auth.password', function ($app) 
            $tokens = $app['auth.password.tokens'];

            $users = $app['auth']->driver()->getProvider();

            $view = $app['config']['auth.password.email'];

            return new PasswordBroker(
                $tokens, $users, $app['mailer'], $view
            );
        );
    


最后在您的config/app.php 文件中删除Illuminate\Auth\Passwords\PasswordResetServiceProvider::class 并将App\Providers\PasswordResetServiceProvider::class 添加到您的'providers' 数组中。

Laravel 现在将使用您的 PasswordBroker 实现,而不是现有的框架,您不必担心修改框架代码。

【讨论】:

感谢@marcus.ramsden 的贡献。我遵循了您的方法,但我似乎无法弄清楚为什么它不起作用。我没有错误。似乎它仍在调用父类的emailResetLink,而不是被覆盖的类。 对不起,我在示例中的错误,在您的服务提供商的注册部分应该是 $this->app->singleton 而不是 $this->app->bind。注册事物的核心服务提供者也是deferred provider。我会尽快更新。 再次感谢您的意见。 $this->app->singleton 也没有做到这一点。仍在调用父方法。 随着更新,它运行良好。 @marcus.ramsden 您对我们很有帮助 @michel3vb 认为应该这样做gist.github.com/jamesfairhurst/a30f034f6aeef45fe32f17e5588c1adf【参考方案2】:

我知道这个问题已经得到解答,但我找到了另一种排队密码重置通知的方法,我发现它更简单。我已经在 Laravel 5.3 和 6.x 上对其进行了测试。

默认情况下,密码重置通知由Illuminate\Auth\Notifications\ResetPassword类实现。此类在 sendPasswordResetNotification 方法中的 User 模型中实例化,并传递给 Illuminate\Notifications\Notifiable trait 的 notify 方法。

因此,要排队密码重置通知,您只需通过artisan make:notification ResetPassword 创建新的ResetPassword 通知类并将其代码替换为:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;

class ResetPassword extends ResetPasswordNotification implements ShouldQueue

    use Queueable;

现在只需覆盖 App\User 类中的 sendPasswordResetNotification 方法:

<?php

...
use App\Notifications\ResetPassword as ResetPasswordNotification;
...    

/**
 * Send the password reset notification.
 *
 * @param  string  $token
 * @return void
 */
public function sendPasswordResetNotification($token)

    $this->notify(new ResetPasswordNotification($token));

【讨论】:

我认为这是最好的和最简单的一个,这个工作就像 L5.4 中的魅力 相关文档:laravel.com/docs/5.5/notifications#queueing-notifications 指定队列:$this-&gt;notify((new ResetPasswordNotification($token))-&gt;onQueue('queue-name')); @fakemeta 这也适用于 Laravel 6 吗?我试图深入研究重置密码,但它对我的小脑袋来说太复杂了 在 laravel 8 微风认证下工作,和实现邮箱验证一样,谢谢【参考方案3】:

如果您在尝试指定队列 fakemeta 的解决方案后得到“在 null 上调用成员函数 onQueue()”,只需在类的构造函数中指定您要定位的队列。

<?php
namespace App;

use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class ResetPasswordNotification extends ResetPassword implements ShouldQueue

    use Queueable;

    public function __construct()
    
        $this->queue = "authentication";
    

然后使用通知外观以覆盖方法发送您的邮件。 notify 方法也有效

<?php
namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\ResetPasswordNotification;

class User extends Authenticatable

    public function sendPasswordResetNotification($token)
    
        // either of the two work
        // $this->notify(new ResetPasswordNotification($token));
        \Notification::send($this, new ResetPasswordNotification($token));
    

【讨论】:

以上是关于如何使用 laravel 5 中的队列通过电子邮件发送密码重置链接的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Laravel 5.1 在 IronMQ 中获取排队作业的数量?

Laravel 5.6队列重启CPU使用率

如何使用 Laravel 5.5 身份验证使电子邮件登录不区分大小写

如何通过邮件方法将数据从 ajax 传输到 laravel 5.2 控制器

laravel 队列守护进程邮件因 SSL 错误而停止运行

如何在laravel 5.2登录时检查电子邮件(确认/否)?