Apply Laravel 5.7 MustVerifyEmail on Multiple Authentication System

一世执手 提交于 2019-12-01 11:04:48

问题


I'm trying to apply Laravel-5.7 MustVerifyEmail on multiple authentication system. So far what I've done is as follows:

  1. created verification routes for the 'auditor' guard.
  2. overwrite the show method in Verification controller with a new view.
  3. Implemented a new notification in Auditor Model.
  4. Created, register and applied a new middleware called 'auditor.verified'

After this procedure, I find that it's sending a notification to email and shows the verify page but when I click on the 'Verify Email Address' button in the mail it update the database with the timestamp but it don't take me to the redirect page. Instead, I get "The page isn't working" message in the browser.

There should be something I missed.

Here is the project file on GitHub

Thanks in advance for your help.


回答1:


M.Islam's answer is a good one, but make sure to override the changes to EnsureEmailIsVerified instead of directly modified the source files. Otherwise your changes could be lost whenever you do $composer update or push to production.




回答2:


Finally, after four days of research I was able to solve the issue.

I altered the "EnsureEmailIsVerified" middleware as follows:

<?php

namespace Illuminate\Auth\Middleware;

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

class EnsureEmailIsVerified
{

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
 */
public function handle($request, Closure $next, $guard = null)
{

    $guards = array_keys(config('auth.guards'));

    foreach($guards as $guard) {

        if ($guard == 'admin') {

            if (Auth::guard($guard)->check()) {

                if (! Auth::guard($guard)->user() ||
                    (Auth::guard($guard)->user() instanceof MustVerifyEmail &&
                    ! Auth::guard($guard)->user()->hasVerifiedEmail())) {
                    return $request->expectsJson()
                            ? abort(403, 'Your email address is not verified.')
                            : Redirect::route('admin.verification.notice');
                }  

            }

        }

        elseif ($guard == 'auditor') {

            if (Auth::guard($guard)->check()) {

                if (! Auth::guard($guard)->user() ||
                    (Auth::guard($guard)->user() instanceof MustVerifyEmail &&
                    ! Auth::guard($guard)->user()->hasVerifiedEmail())) {
                    return $request->expectsJson()
                            ? abort(403, 'Your email address is not verified.')
                            : Redirect::route('auditor.verification.notice');
                }  

            }

        }

        elseif ($guard == 'web') {

            if (Auth::guard($guard)->check()) {

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

                }
            }

        }

        return $next($request);
    }
}

And that's solved my problem.




回答3:


So There was a similar question...

StackOverflow::Route [user.verification.notice] not defined / Override EnsureEmailIsVerified?

when using multiple guards you can just some guard redirection in the

App\Middleware\Authenticate.php

protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        if (Arr::first($this->guards) === 'admin') {
            return route('admin.login');
        }

        if (Arr::first($this->guards) === 'user') {
            return route('user.login');
        }

        return route('login');
    }
}

you can just add all the verify routes to your web.php file and change the named routes.

All auth routes can be found in

Illuminate\Routing\Router.php
\
/**
 * Register the typical authentication routes for an application.
 *
 * @param  array  $options
 * @return void
 */
public function auth(array $options = [])
{
    // Authentication Routes...
    $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
    $this->post('login', 'Auth\LoginController@login');
    $this->post('logout', 'Auth\LoginController@logout')->name('logout');

    // Registration Routes...
    if ($options['register'] ?? true) {
        $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
        $this->post('register', 'Auth\RegisterController@register');
    }

    // Password Reset Routes...
    if ($options['reset'] ?? true) {
        $this->resetPassword();
    }

    // Email Verification Routes...
    if ($options['verify'] ?? false) {
        $this->emailVerification();
    }
}

/**
 * Register the typical reset password routes for an application.
 *
 * @return void
 */
public function resetPassword()
{
    $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
    $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
    $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
    $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
}

/**
 * Register the typical email verification routes for an application.
 *
 * @return void
 */
public function emailVerification()
{
    $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
    $this->get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')->name('verification.verify');
    $this->post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
}

So instead of using the Auth::routes() you would manually add these to your web.php routes file and just give them named routes.

Note: Once you change the named routes you will need to correctly reference them in your views.

The first thing it will complain about is the notifications mail which is referencing the default named routes...

You can over ride this in both the verification mail process and forgot password password by following the example here.

Forgot Password Custom Named Route and Email

To achieve this you would have to override the email notifications by creating two custom ones that override the two default ones.

You would emulate the laravel default structure found in the files

Illuminate\Auth\Notifications\VerifyEmail.php
Illuminate\Auth\Notifications\ResetPassword

Once you have created 2 notifications mailers.

eg

php artisan make:notification MailEmailVerificationNotification

which creates a file in App\Notifications\MailEmailVerificationNotification which effectively replicates the Illuminate\Auth\Notifications\VerifyEmail.php file

You will add the method to your model. Laravel default is User but if you are using custom guards with multiple tenant auth you would apply this to your relevant model.

You will then have the following on you model

/**
 * Send the password reset notification.
 * App\Notifications\MailResetPasswordNotification.php
 *
 * @param  string  $token
 * @return void
 */
public function sendEmailVerificationNotification()
{
    $this->notify(new MailEmailVerificationNotification());
}

Going this route is better because you override the Laravel default logic but you don't edit any Laravel specific files which means they won't get overwritten when updating Laravel and will only be affected when the is design changes like the recent move to extract the Laravel UI into its own package which changed things slightly on the passwords reset route.

you may note that we altered the App\Middleware\Authenticate file... this file is not part of vendor files and while provided to you as part of base install its left for you to alter update and change... the change we made was only to accommodate guards and not extensive change which allows for the multitenancy or not in the app.

For anyone I hope this helps and I went on a journey learning this and hope to reference this when I forget and hope it helps anyone walking a similar path.




回答4:


I modified the middleware parameter in the __construct and email verification worked for me. I'm using laravel 6. posting the answer here though the question is old

public function __construct()
{
    $this->middleware('auth:<your_guard>');
    $this->middleware('signed')->only('verify');
    $this->middleware('throttle:6,1')->only('verify', 'resend');
}


来源:https://stackoverflow.com/questions/53186788/apply-laravel-5-7-mustverifyemail-on-multiple-authentication-system

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!