Create MultiAuth in Laravel 7.x
Steps1:
Scaffold migration and Roles
First
Install laravel project and make scaffold.
Second
·
Add
role_id column in users table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->foreignId('role_id')->constrained();
$table->rememberToken();
$table->timestamps();
});
}
·
Create
roles table
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('nickname',20);
$table->string('name',20);
$table->timestamps();
});
DB::table('roles')->insert(['nickname'=>'admin', 'name'=>'Admin']);
DB::table('roles')->insert(['nickname'=>'user', 'name'=>'User']);
}
Third
In Users
table for just start set role_id
column default 2.
Steps2:
Custom Guard and Provider
1. Go config/auth.php and add guards for user and admin then below add proivders and password
field for admin and user
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
//above for admins I want use same model if you have other model then specify model name
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
2. Go to LoginController
and go to find traits for AuthenticatesUsers.php
in LoginController. And last add the line user.
protected function guard()
{
return Auth::guard('user');
}
3. Go to HomeController and change the middleware (‘auth’) => (‘auth:user’).
Step3:
Routes for Admin and User
1. Search Router.php file
(vendor/laravel/framework/src/illuminate/Routing/Router.php) and find route
like login/register etc...
2. Go to app\http\controller\auth and create folder
inside auth admin and user and copy all file under auth and paste under these
folder and change the path inside controller like for all:
namespace App\Http\Controllers\Auth\Admin;
same for user also but follow if traditional auth file moved
because you have to change these file also in router.php
namespace App\Http\Controllers\Auth\User;
3. Go to Authenticates user for default user and
change the redirect route after logout=> this change is up to you if you want
then okk otherwise this will be okk: optional case
return $request->wantsJson()
? new Response('', 204)
: redirect('/login');
Now for Admin part this is important: Login Controller
<?php
namespace App\Http\Controllers\Auth\Admin;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/admin/dashboard';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
use RedirectsUsers, ThrottlesLogins;
/**
* Show the application's login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view('auth.admin.login');
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
/**
* Validate the user login request.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function validateLogin(Request $request)
{
$request->validate([
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
/**
* Attempt to log the user into the application.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
/**
* Get the needed authorization credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function credentials(Request $request)
{
return $request->only($this->username(), 'password');
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
if ($response = $this->authenticated($request, $this->guard()->user())) {
return $response;
}
return $request->wantsJson()
? new Response('', 204)
: redirect()->intended($this->redirectPath());
}
/**
* The user has been authenticated.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return mixed
*/
protected function authenticated(Request $request, $user)
{
//
}
/**
* Get the failed login response instance.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function sendFailedLoginResponse(Request $request)
{
throw ValidationException::withMessages([
$this->username() => [trans('auth.failed')],
]);
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function username()
{
return 'email';
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
if ($response = $this->loggedOut($request)) {
return $response;
}
return $request->wantsJson()
? new Response('', 204)
: redirect('/login');
}
/**
* The user has logged out of the application.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function loggedOut(Request $request)
{
//
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('admin');
}
}
Make some modification user redirectTo after login => /user/dashboard
4. Make dashboardController for admin and user And
make route for both also make blade file
5. Add construct function in controller for admin and
user.
6. Make auth resource file for admin and change route also also like auth blade file for user.
Step4:
Important and 3 steps problems solved OR exception handler and middleware
·
Change
in layouts/app.blade.php for logout
route
@if(auth()->user()->role->nickname == ‘user’)
@else @endif
·
Search
unauthenticated function in vendor
structure and add into Exception/handler.php
file and make some little modification like this
/**
* Convert an authentication exception into a response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if( $request->expectsJson() )
{
return response()->json(['message' => $exception->getMessage()], 401);
}
$guard = Arr::get( $exception->guards(), 0 );
$route = '';
if ( $guard == 'admin') {
$route = 'admin/login';
}
else if( $guard == 'user') {
$route = 'login';
}
return redirect($route);
}
·
Now go to Middleware=> RedirectIfAuthenticated.php file where we define if admin is logged in then
admin/login page not redirected.
Note:
First go to your auth controller and define guard:admin/user in construct
function.Login Controller
public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}
Add below condition in file: add this into a
middleware file RedirectedifAuthenticated.php
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
// return redirect(RouteServiceProvider::HOME);
//here it will check if admin/user is logged in then then pop up the login page
if ($guard == 'admin') {
return redirect('admin/dashboard');
}
else if($guard == 'user')
{
return redirect('/dashboard');
}
}
return $next($request);
}
·
Final Note: don’t forgot add this add this for both
Admin/User in Admin LoginController and for user LoginController AuthenticatesUsers
trait.
These
methods add between login function of both admin and user.
$user = User::where('email', request()->email)->first();
if ($user AND $user->role->nickname !== 'admin') {
return redirect('/admin/login')->with(['status'=>'Sorry! Invalid Credentials']);
}
Step5:
Forgot password add:
1. Users Section=> main file ForgotPasswordController and ResetPasswordController.
Construct
add in both controller copy and paste it this: same will paste.
In
laravel7.x this function method is not define you have to write or define
manually OR in previous version it already defined:
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:user');
}
Broker
add => users
Find
two file using ForgotPasswordController and ResetPasswordController
·
In SendPasswordResetEmails add broker(‘users’) like below
·
In add ResetPasswords.php file add broker(‘users’) and guard(‘users’) like below
If
you see broker function in files then add like this OR if you see two function
broker and guard then add values like this: these function are already
predefine you don’t have to create, you just have to call value.
public function broker()
{
return Password::broker('users');
}
protected function guard()
{
return Auth::guard('user');
}
2.
Admin Section
§ Forgot password
·
First
create the Admin routes for forgot and reset find in Router.php(vendor
structure)
·
Go
to admin ForgotPasswordController:
o
Same
as login functionality go to trait in forgotpassword copy and paste in forgot
password section and modify the controller file
<?php
namespace App\Http\Controllers\Auth\Admin;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:admin');
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
*/
public function showLinkRequestForm()
{
return view('auth.admin.passwords.email');
}
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$this->credentials($request)
);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($request, $response)
: $this->sendResetLinkFailedResponse($request, $response);
}
/**
* Validate the email for the given request.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function validateEmail(Request $request)
{
$request->validate(['email' => 'required|email']);
}
/**
* Get the needed authentication credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function credentials(Request $request)
{
return $request->only('email');
}
/**
* Get the response for a successful password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkResponse(Request $request, $response)
{
return $request->wantsJson()
? new JsonResponse(['message' => trans($response)], 200)
: back()->with('status', trans($response));
}
/**
* Get the response for a failed password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkFailedResponse(Request $request, $response)
{
if ($request->wantsJson()) {
throw ValidationException::withMessages([
'email' => [trans($response)],
]);
}
return back()
->withInput($request->only('email'))
->withErrors(['email' => trans($response)]);
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('admins');
}
}
·
o
As
well as modify the blade file related to Admin auth controller
o
Now
next create new email file for admin like this: Note: add ResetPasswordNotification function in User Model
o
php artisan
make:notification ResetPasswordNotification
And modigy the
ResetPasswordNotification file like below:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Support\Facades\Lang;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class ResetPasswordNotification extends Notification
{
use Queueable;
public $token;
public $route;
/**
* The callback that should be used to create the reset password URL.
*
* @var \Closure|null
*/
public static $createUrlCallback;
/**
* The callback that should be used to build the mail message.
*
* @var \Closure|null
*/
public static $toMailCallback;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($route, $token)
{
$this->token = $token;
$this->route = $route;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
if (static::$createUrlCallback) {
$url = call_user_func(static::$createUrlCallback, $notifiable, $this->token);
} else {
$url = url(config('app.url').route($this->route, [
'token' => $this->token,
'email' => $notifiable->getEmailForPasswordReset(),
], false));
}
return (new MailMessage)
->subject(Lang::get('Reset Password Notification'))
->line(Lang::get('You are receiving this email because we received a password reset request for your account.'))
->action(Lang::get('Reset Password'), $url)
->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
->line(Lang::get('If you did not request a password reset, no further action is required.'));
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
o
Go
to User Model and add function like
this: In this function I have written some line of code for distinct between
user and admin.
public function sendPasswordResetNotification($token)
{
$route = $this->role->nickname == 'admin' ? 'admin.password.reset' : 'password.reset';
$this->notify(new ResetPasswordNotification( $route, $token));
}
§ Reset Password
ResetsPasswords Go to this Traits and copy all
his code and paste it on ResetPasswordController and modified for Admins
<?php
namespace App\Http\Controllers\Auth\Admin;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use App\Providers\RouteServiceProvider;
use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use RedirectsUsers;
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $token
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.admin.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Reset the given user's password.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
public function reset(Request $request)
{
$request->validate($this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($request, $response)
: $this->sendResetFailedResponse($request, $response);
}
/**
* Get the password reset validation rules.
*
* @return array
*/
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:8',
];
}
/**
* Get the password reset validation error messages.
*
* @return array
*/
protected function validationErrorMessages()
{
return [];
}
/**
* Get the password reset credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function credentials(Request $request)
{
return $request->only(
'email', 'password', 'password_confirmation', 'token'
);
}
/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $password
* @return void
*/
protected function resetPassword($user, $password)
{
$this->setUserPassword($user, $password);
$user->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
$this->guard()->login($user);
}
/**
* Set the user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $password
* @return void
*/
protected function setUserPassword($user, $password)
{
$user->password = Hash::make($password);
}
/**
* Get the response for a successful password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetResponse(Request $request, $response)
{
if ($request->wantsJson()) {
return new JsonResponse(['message' => trans($response)], 200);
}
return redirect($this->redirectPath())
->with('status', trans($response));
}
/**
* Get the response for a failed password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{
if ($request->wantsJson()) {
throw ValidationException::withMessages([
'email' => [trans($response)],
]);
}
return redirect()->back()
->withInput($request->only('email'))
->withErrors(['email' => trans($response)]);
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('admins');
}
/**
* Get the guard to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('admin');
}
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = '/admin/dashboard';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:admin');
}
}
·
Don’t
forgot to modify the blade file
Done
Comments
Post a Comment