【laravel5.7】 MultiAuthにEmailVerificationを対応させる

MultiAuthにEmailVerificationを対応させる実装メモ。

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


MultiAuthなしの実装メモは別記事で書いているので、参考になれば、、、

【laravel5.7】 Email Verificationの使い方



やりたいこと

MultiAuth(Admin/User)のUserのみにEmail Verificationを対応させたい。


環境

MacOS 10.14.3

VisualStudio

laravel 5.7


Email Verificationを使えるようにする


MustVerifyEmailの追加


app/User.php

<?php

namespace App;

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

+class User extends Authenticatable implements MustVerifyEmail
{



ルーティング設定


routes/web.php

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

use Illuminate\Http\Request;

Route::get('/', function () {
return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');
// 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');
});

// Admin
以下省略


単体ログインのEmailVerificationのAuth:routes(['verify'=>true]);

MultiAuthでは上の(//emailverify以下の部分)のように一つずつ書いていきます。


VerificationController.php


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

<?php

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

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

class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/

use VerifiesEmails;

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

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
+ $this->middleware('auth:user');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}

+ public function show(Request $request)
+ {
+ return $request->user()->hasVerifiedEmail()
+ ? redirect($this->redirectPath())
+ : view('user.auth.verify');
+ }
}



HomeController.php


app/Http/Controllers/User/HomeController.php

    public function __construct()

{
$this->middleware('auth:user');
+ $this->middleware('allVerified');
}


Middleware

AllEnsureEmailIsVerified.phpを作成します


terminal

php artisan make:middleware AllEnsureEmailIsVerified



app/Http/Middleware/AllEnsureEmailIsVerified.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Auth;

class AllEnsureEmailIsVerified
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/

public function handle($request, Closure $next)
{
$guards = array_keys(config('auth.guards'));

foreach($guards as $guard) {
if($guard == 'user') {
if (Auth::guard($guard)->check()) {
if (! Auth::guard($guard)->user() ||
(Auth::guard($guard)->user() instanceof MustVerifyEmail &&
! Auth::guard($guard)->user()->hasVerifiedEmail())) {
// dd('ddd');
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: Redirect::route('user.verification.notice');
}
}
}
}
return $next($request);
}
}



Kernel.php


app/Http/Kernel.php

    protected $routeMiddleware = [

'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
+ 'allVerified' => \App\Http\Middleware\AllEnsureEmailIsVerified::class,
];


verify.blade.php


views/user/auth/verify.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">{{ __('メールアドレスの認証') }}</div>

<div class="card-body">
@if (session('resent'))
<div class="alert alert-success" role="alert">
{{ __('認証メールを再送信しました。') }}
</div>
@endif

{{ __('メールアドレスの認証をしてください。') }}
+ {{ __('もしメールを受け取ってないなら、<a href="{{ route('user.verification.resend') }}">ここをクリックしてください</a>。') }}
</div>
</div>
</div>
</div>
</div>
@endsection



メール内容をカスタマイズ


Notificationsの作成


terminal

php artisan make:notification UserVerifyEmailNotification



app/Notifications/UserVerifyEmailNotification.php

<?php

namespace App\Notifications;

use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailNotification;
use Illuminate\Notifications\Messages\MailMessage;

use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Lang;

class UserVerifyEmailNotification extends VerifyEmailNotification
{
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable);
}

return (new MailMessage)
->subject(Lang::getFromJson('USERメール確認'))
->line(Lang::getFromJson('クリックして認証してください.'))
->action(
Lang::getFromJson('メール認証'),
$this->verificationUrl($notifiable)
)
->line(Lang::getFromJson('もしこのメールに覚えが無い場合は破棄してください。'));
}

protected function verificationUrl($notifiable)
{
return URL::temporarySignedRoute(
'user.verification.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()]
);
}
}



User.php

UserVerifyEmailNotificationがメールで送信されるように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\UserVerifyEmailNotification;

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 sendEmailVerificationNotification()
+ {
+ $this->notify(new UserVerifyEmailNotification);
+ }
}



動作確認

User

http://127.0.0.1:8000/user/register から新しくアカウントを登録します。

web

スクリーンショット 2019-03-01 11.27.52.png

登録したメールアドレス

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

メール認証ボタンクリックすると、

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235323636372f37653335643530392d353037382d663966382d653163332d6335396463303931653936382e706e67.png

こうなれば成功です。

まだ英語の部分があるので、その辺の設定は後々設定しようと思います。

Adminでも実装したい場合はこれと同様に編集すればOK。

とりあえず以上です。