在多重身份验证系统上应用 Laravel 5.7 MustVerifyEmail

Apply Laravel 5.7 MustVerifyEmail on Multiple Authentication System

我正在尝试在多重身份验证系统上应用 Laravel-5.7 MustVerifyEmail。到目前为止,我所做的如下:

  1. 为 'auditor' 守卫创建了验证路线。
  2. 用新视图覆盖 Verification 控制器中的 show 方法。
  3. 在 Auditor 模型中实现了新的通知。
  4. 创建、注册并应用了一个名为 'auditor.verified'
  5. 的新中间件

完成此过程后,我发现它正在向电子邮件发送通知并显示验证页面,但是当我单击邮件中的 'Verify Email Address' 按钮时,它会使用时间戳更新数据库,但它不会带我到重定向页面。相反,我在浏览器中收到 "The page isn't working" 消息。

应该是我漏掉了什么。

这是 GitHub

上的 project file

在此先感谢您的帮助。

经过四天的研究,我终于解决了这个问题。

我修改了 "EnsureEmailIsVerified" 中间件如下:

<?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);
    }
}

这就解决了我的问题。

M.Islam 的回答很好,但请确保覆盖对 EnsureEmailIsVerified 的更改,而不是直接修改源文件。否则,每当您执行 $composer 更新或推送到生产环境时,您的更改可能会丢失。

所以有一个类似的问题...

当使用多个守卫时,你可以在

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');
    }
}

您可以将所有验证路由添加到您的 web.php 文件并更改命名路由。

所有授权路由都可以在

中找到
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');
}

因此,您无需使用 Auth::routes(),而是手动将这些添加到您的 web.php 路由文件中,并只给它们命名路由。

注意:更改命名路由后,您需要在视图中正确引用它们。

它会抱怨的第一件事是引用默认命名路由的通知邮件...

您可以按照此处的示例在验证邮件过程和忘记密码密码中克服此问题。

Forgot Password Custom Named Route and Email

要实现此目的,您必须通过创建两个覆盖两个默认通知的自定义通知来覆盖电子邮件通知。

您将模拟在文件

中找到的 laravel 默认结构
Illuminate\Auth\Notifications\VerifyEmail.php
Illuminate\Auth\Notifications\ResetPassword

一旦您创建了 2 个通知邮件程序。

例如

php artisan make:notification MailEmailVerificationNotification

在 App\Notifications\MailEmailVerificationNotification 中创建一个文件,该文件有效地复制了 Illuminate\Auth\Notifications\VerifyEmail.php 文件

您将该方法添加到您的模型中。 Laravel 默认为用户,但如果您使用具有多租户身份验证的自定义守卫,您可以将其应用于您的相关模型。

然后您的模型将拥有以下内容

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

走这条路更好,因为您覆盖了 Laravel 默认逻辑,但您没有编辑任何 Laravel 特定文件,这意味着它们在更新 Laravel 时不会被覆盖并且只会在 is 设计发生变化时受到影响,例如最近将 Laravel UI 提取到自己的包中,这在密码重置路径上略有改变。

您可能会注意到我们更改了 App\Middleware\Authenticate 文件...此文件不是供应商文件的一部分,虽然作为基本安装的一部分提供给您,但它留给您更改更新和更改.. .我们所做的更改只是为了容纳守卫,而不是允许或不允许在应用程序中使用多租户的广泛更改。

对于任何人,我希望这对任何人都有帮助,我开始了学习这个的旅程,希望在我忘记时参考它,并希望它能帮助任何走类似道路的人。

我修改了 __construct 中的中间件参数,电子邮件验证对我有用。我正在使用 laravel 6。虽然问题很旧,但在这里发布答案

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