PHP
Laravel

【laravel5.7】MultiAuthにパスワードリセットを追加する

MultiAuthにパスワードリセットを追加する実装メモ

【laravel5.7】 MultiAuthログインの続きとして書きます。


やりたいこと

User/Adminそれぞれにパスワードリセットを実装したい


環境

MacOS 10.14.3

VisualStudio

laravel 5.7


Admin側の設定


auth.php

リセット用のtokenを保存するテーブルが必要なので、auth.phpで設定します。


config/auth.php


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

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



Controller


ForgotPasswordController.php


app/Http/Controllers/Admin/Auth/ForgetPasswordController.php

<?php

+namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;

class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/

use SendsPasswordResetEmails;

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
+ $this->middleware('guest:admin');
}

+ public function showLinkRequestForm()
+ {
+ return view('admin.auth.passwords.email');
+ }

+ protected function guard()
+ {
+ return \Auth::guard('admin');
+ }

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



ResetPasswordController.php


app/Http/Controllers/Admin/Auth/ResetPasswordController.php

<?php

+namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
+use Illuminate\Http\Request;

class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/

use ResetsPasswords;

/**
* Where to redirect users after resetting their password.
*
* @var string
*/
+ protected $redirectTo = '/admin/home';

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
+ $this->middleware('guest:admin');
}

+ public function showResetForm(Request $request, $token = null)
+ {
+ return view('admin.auth.passwords.reset')->with(['token' => $token,'email' => $request->email]);
+ }

+ protected function guard()
+ {
+ return \Auth::guard('admin');
+ }

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



Views


email.blade.php


resources/views/admin/auth/passwords/email.blade.php

+@extends('layouts.admin.auth')


@section('auth')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card mx-4">
<div class="card-body p-4">
<h2>{{ __('Reset Password') }}</h2>
<p class="text-muted">リセットURLを送信します。</p>
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif

+ <form method="POST" action="{{ route('admin.password.email') }}">
@csrf
<div class="col-auto">

<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">@</div>
</div>
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required>
</div>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif

<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection



reset.blade.php


resources/views/admin/auth/passwords/reset.blade.php

+@extends('layouts.admin.auth')


@section('auth')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card mx-4">
<div class="card-body p-4">
<h2>{{ __('Reset Password') }}</h2>

{{-- <div class="card-body"> --}}
+ <form method="POST" action="{{ route('admin.password.update') }}">
@csrf

<input type="hidden" name="token" value="{{ $token }}">
<div class="col-auto">

<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">Email</div>
</div>
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" required autofocus>
</div>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif

</div>

<div class="col-auto">

<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-key"></i></div>
</div>
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>

@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>

</div>

<div class="col-auto">

<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-key"></i></div>
</div>
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
</div>
</div>

<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
{{-- </div> --}}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection



ルーティング


web.php


routes/web.php

// Admin

Route::group(['namespace' => 'Admin','prefix'=>'admin'],function(){
// home
Route::get('home','HomeController@index')->name('admin.home');

// login logout
Route::get('login','Auth\LoginController@showLoginForm')->name('admin.login');
Route::post('login','Auth\LoginController@login')->name('admin.login');
Route::post('logout','Auth\LoginController@logout')->name('admin.logout');

// register
Route::get('register','Auth\RegisterController@showRegisterForm')->name('admin.register');
Route::post('register','Auth\RegisterController@register')->name('admin.register');

+ // password resets
+ Route::post('password/email','Auth\ForgotPasswordController@sendResetLinkEmail')->name('admin.password.email');
+ Route::post('password/reset','Auth\ResetPasswordController@reset')->name('admin.password.request');
+ Route::get('password/reset','Auth\ForgotPasswordController@showLinkRequestForm')->name('admin.password.update');
+ Route::get('password/reset/{token}','Auth\ResetPasswordController@showResetForm')->name('admin.password.reset');
});



送信機能のオーバーライド

AdminPasswordResetNotification.phpを作ります。


terminal

php artisan make:notification AdminPasswordResetNotification



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('ADMINパスワードリセット用メール.')
->action('Reset Password', url(config('url').route('admin.password.reset', $this->token, false)))
->line('If you did not request a password reset, no further action is required.');
}
}



Admin.phpの変更

AdminPasswordResetNotificationがメールで送信されるようにModelに設定します。


app/Admin.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

+use App\Notifications\AdminPasswordResetNotification;

class Admin extends Authenticatable
{
use Notifiable;

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password','api_token'
];

/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];

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



動作確認

http://127.0.0.1:8000/admin/login

web

スクリーンショット 2019-02-28 12.56.33.png

入力したメールアドレス

スクリーンショット 2019-02-28 12.56.54.png

Reset Passwordボタンをクリック

スクリーンショット 2019-02-28 13.07.58.png

こんな感じで動けばOK


User側の設定

Adminとやることは変わりません


Controller


ForgotPasswordController.php


app/Http/Controllers/User/Auth/ForgetPasswordController.php

<?php

+namespace App\Http\Controllers\User\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;

class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/

use SendsPasswordResetEmails;

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
+ $this->middleware('guest:user');
}

+ public function showLinkRequestForm()
+ {
+ return view('user.auth.passwords.email');
+ }

+ protected function guard()
+ {
+ return \Auth::guard('user');
+ }

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



ResetPasswordController.php


app/Http/Controllers/User/Auth/ResetPasswordController.php

<?php

+namespace App\Http\Controllers\User\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
+use Illuminate\Http\Request;

class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/

use ResetsPasswords;

/**
* Where to redirect users after resetting their password.
*
* @var string
*/
+ protected $redirectTo = '/user/home';

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
+ $this->middleware('guest:user');
}

+ public function showResetForm(Request $request, $token = null)
+ {
+ return view('user.auth.passwords.reset')->with(['token' => $token,'email' => $request->email]);
+ }

+ protected function guard()
+ {
+ return \Auth::guard('user');
+ }

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



Views


email.blade.php


resources/views/user/auth/passwords/email.blade.php

+@extends('layouts.user.app')


@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>

<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif

+ <form method="POST" action="{{ route('user.password.email') }}">
@csrf

<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required>

@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>

<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection



reset.blade.php


resources/views/user/auth/passwords/reset.blade.php

+@extends('layouts.user.app')


@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>

<div class="card-body">
+ <form method="POST" action="{{ route('user.password.update') }}">
@csrf

<input type="hidden" name="token" value="{{ $token }}">

<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" required autofocus>

@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>

<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>

@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>

<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
</div>
</div>

<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection



ルーティング


web.php


routes/web.php

// User

Route::group(['namespace' => 'User','prefix'=>'user'],function(){
Route::get('/',function(){
return redirect()->to('user/home');
})->name('user');
// home
Route::get('home','HomeController@index')->name('user.home');

// login lgoout
Route::get('login','Auth\LoginController@showLoginForm')->name('user.login');
Route::post('login','Auth\LoginController@login')->name('user.login');
Route::post('logout','Auth\LoginController@logout')->name('user.logout');

// register
Route::get('register','Auth\RegisterController@showRegisterForm')->name('user.register');
Route::post('register','Auth\RegisterController@register')->name('user.register');

// emailverify
Route::middleware('throttle:6,1')->get('email/resend','Auth\VerificationController@resend')->name('user.verification.resend');
Route::middleware('throttle:6,1')->get('email/verify','Auth\VerificationController@show')->name('user.verification.notice');
Route::middleware('signed')->get('email/verify/{id}','Auth\VerificationController@verify')->name('user.verification.verify');

+ // password reset
+ Route::post('password/email','Auth\ForgotPasswordController@sendResetLinkEmail')->name('user.password.email');
+ Route::post('password/reset','Auth\ResetPasswordController@reset')->name('user.password.request');
+ Route::get('password/reset','Auth\ForgotPasswordController@showLinkRequestForm')->name('user.password.update');
+ Route::get('password/reset/{token}','Auth\ResetPasswordController@showResetForm')->name('user.password.reset');
});



送信機能のオーバーライド

UserPasswordResetNotification.phpを作ります。


terminal

php artisan make:notification UserPasswordResetNotification



app/Notifications/UserPasswordResetNotification.php

<?php

namespace App\Notifications;

use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
use Illuminate\Notifications\Messages\MailMessage;

class UserPasswordResetNotification extends ResetPasswordNotification
{
public function toMail($notifiable)
{
return (new MailMessage)
->line('USERパスワードリセット用メール.')
->action('Reset Password', url(config('url').route('user.password.reset', $this->token, false)))
->line('If you did not request a password reset, no further action is required.');
}
}



User.phpの変更

UserPasswordResetNotificationがメールで送信されるようにModelに設定します。


app/User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

+use App\Notifications\UserPasswordResetNotification;

class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];

/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];

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



動作確認

http://127.0.0.1:8000/user/login

Adminと同じように動けばOKです。

メール内容

スクリーンショット 2019-02-28 12.57.22.png

以上です。