2

Here,I m implementing multi auth and i have two guards user and admin auth.php

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session", "token"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Models\Admin::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

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

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

I thankfully able to implement email verification for admin side this way: EmailVerifyController.php

<?php

namespace App\Http\Controllers;

use App\Models\Admin;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Auth\Events\Verified;
use Illuminate\Auth\Access\AuthorizationException;

class EmailVerifyController extends Controller
{   
    public function __construct()
    {
        $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('AdminAuth.verify');
    }

    /**
     * Mark the authenticated user's email address as verified.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
     *
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function verify(Request $request)
    {   
        $user = Admin::findOrFail($request->id);
        if (! hash_equals((string) $request->route('id'), (string) $user->getKey())) {
            throw new AuthorizationException;
        }

        if (! hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
            throw new AuthorizationException;
        }

        if ($user->hasVerifiedEmail()) {
            return $request->wantsJson()
                        ? new JsonResponse([], 204)
                        : redirect('/admin/login');
        }

        if ($user->markEmailAsVerified()) {
            event(new Verified($request->user()));
        }

        if ($response = $this->verified($request)) {
            return $response;
        }

        return $request->wantsJson()
                    ? new JsonResponse([], 204)
                    : redirect($this->redirectPath())->with('verified', true);
    }

    /**
     * The user has been verified.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    protected function verified(Request $request)
    {
        //
    }

    /**
     * Resend the email verification notification.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
     */
    public function resend(Request $request)
    {
        if ($user->hasVerifiedEmail()) {
            return $request->wantsJson()
                        ? new JsonResponse([], 204)
                        : redirect($this->redirectPath());
        }

        $user->sendEmailVerificationNotification();

        return $request->wantsJson()
                    ? new JsonResponse([], 202)
                    : back()->with('resent', true);
    }
    public function redirectPath()
    {
        if (method_exists($this, 'redirectTo')) {
            return $this->redirectTo();
        }

        return property_exists($this, 'redirectTo') ? $this->redirectTo :'/admin/login';
    }
}

And this is my web.php

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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!
|
*/

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

Auth::routes();

Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/admin/login', [App\Http\Controllers\AdminController::class, 'LoginView'])->name('admin.login');
Route::get('/admin/register', [App\Http\Controllers\AdminController::class, 'RegisterView'])->name('admin.register');
Route::post('/admin/register', [App\Http\Controllers\AdminController::class, 'Register']);
Route::post('/admin/login', [App\Http\Controllers\AdminController::class, 'Login']);
Route::post('/admin/logout', [App\Http\Controllers\AdminController::class, 'logout'])->name('admin.logout');
Route::get('/admin/profile',[App\Http\Controllers\AdminController::class, 'Profile'])->middleware('admin.auth:admin');
Route::get('/admin/forgot-password',[App\Http\Controllers\ForgetPasswordController::class, 'ForgetPassView'])->name('password.request');
Route::post('/admin/forgot-password',[App\Http\Controllers\ForgetPasswordController::class, 'SendResetLink'])->name('password.email');
Route::get('/admin/reset-password/{token}',[App\Http\Controllers\ResetPasswordController::class, 'showResetForm'])->name('admin.password.reset');
Route::post('/admin/reset-password',[App\Http\Controllers\ResetPasswordController::class, 'reset'])->name('password.update');
Route::post('/admin/email/verification/resend',[App\Http\Controllers\EmailVerifyController::class, 'resend'])->name('verification.resend');
Route::get('/admin/email/verify',[App\Http\Controllers\AdminController::class,'show'])->name('verification.notice');
Route::get('/admin/email/{id}/{hash}',[App\Http\Controllers\EmailVerifyController::class,'verify'])->name('verification.verify');

And i have implements has mustverifyEmail on both user and admin model but problem is when i register in user side by url :http://127.0.0.1:8000/register i get verifyEmail with verifyButton having url

 http://127.0.0.1:8000/admin/email/1/4af99914b67ad031f0ea1435a9018abe1e6f2a24?expires=1606980103&signature=c68af63dffeac9f8b729962b1f299d23de63bc12e30bde684544a1acf6bdc582
but this is for admin purpose i need somehow this for user
http://127.0.0.1:8000/email/1/4af99914b67ad031f0ea1435a9018abe1e6f2a24?expires=1606980103&signature=c68af63dffeac9f8b729962b1f299d23de63bc12e30bde684544a1acf6bdc582
so i found that on registering user also it is using verification.verify route but i used that for admin 

So how can i make another separate verification for user which follow different url as i can't make another verification.verify route for user , here both guard is using same route .. Help me to solve it please?

Gunaraj Khatri
  • 153
  • 3
  • 13
  • it's something todo with `vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php` but still looking for more info on how to setup `$createUrlCallback` – Saifallak Aug 07 '22 at 15:52

1 Answers1

0

the only way to change url is to use createUrlUsing function on reset password and verify email like the following

        ResetPassword::createUrlUsing(function ($notifiable, string $token) {
            return route('filament.password.reset', [
                'token' => $token,
                'email' => $notifiable->getEmailForPasswordReset(),
            ]);
        });

        VerifyEmail::createUrlUsing(function ($notifiable) {
            return URL::temporarySignedRoute(
                'filament.verification.verify',
                Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
                [
                    'id' => $notifiable->getKey(),
                    'hash' => sha1($notifiable->getEmailForVerification()),
                ]
            );
        });

in any service provider ex: AppServiceProvider

but this overrides the reset/verify for all guards together. so to achieve what you're seeking. you have to create two notification channels like the following

<?php

namespace App\Notifications;

use Illuminate\Auth\Notifications\VerifyEmail as BaseVerifyEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;

class VerifyEmailForAdmins extends BaseVerifyEmail implements ShouldQueue
{
    use Queueable;

    /**
     * Get the verification URL for the given notifiable.
     *
     * @param  mixed  $notifiable
     * @return string
     */
    protected function verificationUrl($notifiable)
    {
        if (static::$createUrlCallback) {
            return call_user_func(static::$createUrlCallback, $notifiable);
        }

        return URL::temporarySignedRoute(
            'verification.verify', // or whatever route name you like/implemented
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }
}

and in App\Models\Admin you just add this method



    public function sendEmailVerificationNotification()
    {
        $this->notify(new VerifyEmailForAdmins);
    }

and then repeat the steps for each guard and also for each Verify and Reset notifications

Saifallak
  • 1,234
  • 2
  • 13
  • 28