Laravel 9. Аутентификация из разных таблиц
Иногда возникает необходимость организовать аутентификацию на сайте из разных таблиц. Например, при создании магазина, меня не устраивает то, что клиенты и менеджеры (администраторы) лежат вперемежку в одной таблице. Да и вход в админку (которая лежит на поддомене) лучше "замкнуть" на отдельную таблицу в которой хранятся учетные записи сугубо администраторов.
Создаем модель Admin (сразу с миграцией). По сути они представляют собой копию модели и миграциии User.
php artisan make:model Admin -m
:
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateAdminsTable extends Migration
{
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::drop('admins');
}
}
Запускаем: php artisan migrate
В самом минимальном виде модель админа будет работать в таком виде:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use HasFactory;
protected $guard = "admin";
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
}
Illuminate\Database\Eloquent\Model
как это присуще обычным моделям, а расширяет Illuminate\Foundation\Auth\User
. Это важный момент.
Настраиваем guard в файле config/auth.php.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin' =>[
'driver' => 'session',
'provider' => 'admins',
]
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => AppUser::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => AppAdminAdmin::class,
]
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
Далее, в контроллер аутентификация LoginController, добавляем методы для входа администратора:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->middleware('guest:admin')->except('logout');
}
public function showAdminLoginForm()
{
return view('auth.login', ['route' => route('admin.login'), 'title'=>'Admin']);
}
public function adminLogin(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:6'
]);
if ($this->guard()
->attempt($request->only(['email','password']), $request->get('remember'))
) {
return redirect()->intended('/admin/dashboard');
}
return back()->withInput($request->only('email', 'remember'));
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('admin');
}
}
Немного изменим представление login.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ $title ?? "" }} {{ __('Login') }}</div>
<div class="card-body">
@isset($route)
<form method="POST" action="{{ $route }}">
@else
<form method="POST" action="{{ route('login') }}">
@endisset
@csrf
...
Далее необходимо изменить метод перенаправления после успешного входа в систему. Это делается в middleware RedirectIfAuthenticated
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @param string|null ...$guards
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if ($guard == "admin" && Auth::guard($guard)->check()) {
return redirect('/admin/dashboard');
}
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}
Если требуется регистрация для админов - добавляем методы в RegisterController:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Admin;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
$this->middleware('guest:admin');
}
// ... Other methods
public function showAdminRegisterForm()
{
return view('auth.register', ['route' => route('admin.register'), 'title'=>'Admin']);
}
protected function createAdmin(Request $request)
{
$this->validator($request->all())->validate();
$admin = Admin::create([
'name' => $request['name'],
'email' => $request['email'],
'password' => Hash::make($request['password']),
]);
return redirect()->intended('admin');
}
}
И соответственно изменяем register.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ $title ?? "" }} {{ __('Register') }}</div>
<div class="card-body">
@isset($route)
<form method="POST" action="{{ $route }}">
@else
<form method="POST" action="{{ route('register') }}">
@endisset
@csrf
...
Осталось только прописать маршруты в файле routes/web.php.
Auth::routes();
Route::get('/admin', 'Auth\LoginAdminController@showAdminLoginForm')->name('admin.login-form');
Route::post('/admin', 'Auth\LoginAdminController@adminLogin')->name('admin.login');
Route::get('/admin/register', 'Auth\RegisterController@showAdminRegisterForm')->name('admin.register-form');
Route::post('/admin/register', 'Auth\RegisterController@createAdmin')->name('admin.register');
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::get('/admin/dashboard',function(){
return view('admin');
})->middleware('auth:admin');
Проверить пользователей теперь можно так:
@if(auth()->guard('admin')->check())
Hello {{auth()->guard('admin')->user()->name}}
@elseif(auth()->guard('web')->check())
Hello {{auth()->guard('web')->user()->name}}
@endif
Важлива інформація
України
втрати противника
орієнтовно склали: