Laravel マルチ認証にてパスワードリセットのメールのリンクがおかしかった。


Laravel5.4でマルチ認証
とかを参考にマルチ認証を実装していたら、パスワードリセットのメールのリンク先がおかしかった。

やりたかったこと

  • /user 以下に一般ユーザ様用の認証付きページがある
  • /admin 以下に管理者様用の認証付きページある
  • Laravelが用意している php artisan make:auth を利用する
  • それぞれ Forgot Your Password? のリンク(下の画像)からパスワードをリセットできる
  • 受信したパスワードリセットのメールからは、userまたはadminかに応じて /user/password/reset/xxx/admin/password/reset/xxx にリンクする

普通に実装した場合

↓のようなメールが届くのですが

/user/password/reset/admin/password/reset それぞれで再発行し、受信したメールは両方とも、
/user/password/reset/xxx にリンクされてしまいました。

対応策

config/auth.php にadmin用の (passwords) brokerを設定したと思います。

config/auth.php



    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        'admins' => [
            'provider' => 'admins',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],


それを admin 用の ResetPasswordController に設定します。

Controllers/Admin/Auth/ResetPasswordController.php


    public function broker()
    {
        return \Password::broker('admins');
    }



ForgotPasswordController にも設定します。

Controllers/Admin/Auth/ForgotPasswordController.php


    public function broker()
    {
        return \Password::broker('admins');
    }



ここからがポイントです。
パスワードリセットメールは基本的に Illuminate\Auth\Notifications\ResetPasswordtoMail() によって発信されます。
これを頑張ってOverrideします。

まず、app 以下に app/Notifications のようにディレクトリを作成し、
ResetPassword classを継承した AdminPasswordResetNotification を作成します。

そうすると、 toMail() をOverrideできますので、そこで admin.password.reset のルーティングを打ち込みます。
以下のようにします。

app/Notifications/AdminPasswordResetNotification.php

<?php
namespace App\Notifications;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
use Illuminate\Notifications\Messages\MailMessage;

class AdminPasswordResetNotification extends ResetPasswordNotification
{
    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->line('You are receiving this email because we received a password reset request for your account.')
            ->action('Reset Password', url(config('app.url').route('admin.password.reset', $this->token, false)))
            ->line('If you did not request a password reset, no further action is required.');
    }
}

これが作成できたら、今度は Admin モデルにて、 sendPasswordResetNotification メソッドをOverrideして、作成したクラスをぶちこみます。

app/Admin.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Notifications\AdminPasswordResetNotification;

class Admin extends Authenticatable
{
    use Notifiable;

    public function sendPasswordResetNotification($token)
    {
        $this->notify(new AdminPasswordResetNotification($token));
    }
}

これで動くはず

まとめ

とりあえず内部のコードを読んで適当にOverrideすればなんとかなる。