问题
I'm trying to apply Laravel-5.7 MustVerifyEmail on multiple authentication system. So far what I've done is as follows:
- created verification routes for the 'auditor' guard.
- overwrite the show method in Verification controller with a new view.
- Implemented a new notification in Auditor Model.
- 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