Laravel Multi Auth using different tables [part 1: User authentication]
Links:
The codes of this video here on GitHub;
Appropriate YouTube video;
YouTube video-lessons Playlist;
You can download the public resources from here;
Part 2: Admin Authentication;
Part 3: Admin Roles/Permissions;
Introduction:
After implementing the same functionality in many projects, I’ve decided to write article about that.
This article will help you to build multiauth boilerplate Laravel app for versions (especially for latest versions: 5.6, 5.7, 5.8). In the end you’ll have an app, which will have user & admin Web authentications functionality. Behind the scenes the clients’ (users/admins) data will be stored in different tables. So users & admins can access their contents from different URIs (different addresses for sign in/out/up).
I already seen and read many other articles about this, but every time something was missed or I had to add or change something for myself.
This article will have 3 parts, so I’ll put here links to other parts.
I hope, that this can be useful for beginners, which will read and understand how to build, or for experienced developers, which will use written code blocks for their projects.
So, let’s get started!
Requirements:
PHP ≥ 7.1.3
Git
Composer
Virtual Host / Homestead / Valet / or something like that
Installation:
Download the latest laravel version at the current time via composer:composer create-project --prefer-dist laravel/laravel laravel-multiauth
Create MySQL (5.7 in my case) DB. Write DB credentials in your “.env” like this:
DB_DATABASE="laravel-multiauth"
DB_USERNAME=root
DB_PASSWORD="secret"
Setup your host. This step you need to do for yourself. I hope you’ll do this.
For me: I just have runned “http://laravel-multiauth.local/” host for testing.
Recommended:
Install this additional package (this is an optional step) created by me, which will help you on development process:composer require boolfalse/clearcaches
You can run the command (see below) every time when you want to be sure, that you have cleared all your app caches.php artisan clearcaches
Also you can use the command (see below) for make your DB as empty.php artisan droptables
If you don’t have APP_KEY initialized in your “.env”, run this:php artisan key:generate
Run this command for refreshing your app caches:php artisan clearcaches
Recommended:
Also if you working with Git, you may have to ignore some unnecessary staff (for example: “.idea” directory for me, as I working with PhpStorm IDE).
So you can visit gitignore.io and grab your generated .gitignore content from there.
If you new there, you just can write some specific tags in the field (“laravel”, “phpstorm+all”, “webstorm+all” for me) and press “Create” button.
It will create your .gitignore content for you for your specific reasons.
Now just run your migrations for having DB tables (especially “users” table) via this command:php artisan migrate
Visit your site’s main page and make sure that you’ve successfully installed and configured your laravel app, and have working state at this moment.
Default Authentication:
Let’s create our default authentication system (provided by Laravel) usingphp artisan make:auth
After this you’ll get some new staff:
New Controller:
app/Http/Controllers/HomeController.php
New Blade Views:
resources/views/auth/…
resources/views/layouts/…
resources/views/home.blade.php
Changed Routes:
routes/web.php
You can check that your site now have some ready staff for Authentication system (Login, Logout, Register, etc).
Models Replacement:
Create “app/Models/” directory and store all your models in there (including existing User model). Move “app/User.php” to “app/Models/User.php”.
After replacing, you’ll have this:
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Also we must to change all usages of User model in whole app. I’ll replace all “App\User” matches with “App\Models\User” via PhpStorm.
So (apart from “app/Models/User.php”) I’ll get following files changed:
config/auth.php
app/Htpp/Controllers/RegisterController.php
config/services.php
database/factories/UserFactory.php
Clear config caches (via “optimize”, “config:cache” or just “clearcaches”) usin artisan commands.
Controllers Replacement:
Apart from general “app/Http/Controllers/Controller.php”, in this step we’ll move some existing controllers from “app/Http/Controllers/” to “app/Http/Controllers/User/” new directory.
We’ll rename “HomeController” to “UserController”.
After all these changes we’ll have this:
app\Http\Controllers\User\Auth\ForgotPasswordController.php
<?php
namespace App\Http\Controllers\User\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;
public function __construct()
{
$this->middleware('guest');
}
}
app\Http\Controllers\User\Auth\LoginController.php
<?php
namespace App\Http\Controllers\User\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
app\Http\Controllers\User\Auth\RegisterController.php
<?php
namespace App\Http\Controllers\User\Auth;
use App\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
use RegistersUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest');
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:6', 'confirmed'],
]);
}
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}
app\Http\Controllers\User\Auth\ResetPasswordController.php
<?php
namespace App\Http\Controllers\User\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest');
}
}
app\Http\Controllers\User\Auth\VerificationController.php
<?php
namespace App\Http\Controllers\User\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
use VerifiesEmails;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}
app\Http\Controllers\User\UserController.php
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('home');
}
}
Routes Replacement:
But all these means that we must change our default routes (generated by “make:auth” command) in “routes/web.php”. I’m about this: Auth::routes();
which we can replace with appropriate collection of routes. So we’ll have this:
<?php
Route::get('/', function () {
return view('welcome');
})->name('front');
Route::group([
'namespace' => 'User\\Auth',
], function () {
// Authentication Routes...
Route::get('login', 'LoginController@showLoginForm')->name('login_page');
Route::post('login', 'LoginController@login')->name('login');
Route::post('logout', 'LoginController@logout')->name('logout');
// Registration Routes...
Route::get('register', 'RegisterController@showRegistrationForm')->name('register_page');
Route::post('register', 'RegisterController@register')->name('register');
Route::get('register/activate/{token}', 'RegisterController@confirm')->name('email_confirm');
// Password Reset Routes...
Route::get('password/reset', 'ForgotPasswordController@showLinkRequestForm')->name('password.request');
Route::post('password/email', 'ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::get('password/reset/{token}', 'ResetPasswordController@showResetForm')->name('password.reset');
Route::post('password/reset', 'ResetPasswordController@reset');
});
Route::get('home', 'User\\UserController@index')->name('home');
Note:
Keep in mind, that we’ve added “User\\” prefix before all controllers in each route. Later we’ll remove that, and we’ll use that from Route Service Provider.
As you can see, we also made an alias for first route of our “web.php”. It means that we can replace and use “route(‘front’)” instead of “url(‘/’)” in “resources/views/layouts/app.php”.
Also don’t forget to replace “route(‘login’)” & “route(‘register’)” href links in “resources/views/layouts/app.blade.php” and “resources/views/welcome.blade.php” to “route(‘login_page’)” & “route(‘register_page’)” appropriately.
Now make sure that you have working state. If you got some problems, then please read and use all codes on top again, cuz later may I’ll not show all code staff. Instead I’ll show only changed staff.
Blade Views Replacement:
Let’s move all these staff (see below) from “resources/views” to new directory “resources/views/user/”
auth/passwords/email.blade.php
auth/passwords/reset.blade.php
auth/login.blade.php
auth/register.blade.php
auth/verify.blade.php
layouts/app.blade.php
home.blade.php
Find all “@extends(‘layouts.app’)” matches in path “resources/views/user/”, and replace that with “@extends(‘user.layouts.app’)”.
Also this means that we must to change all views paths returned from controllers by default.
Laravel have built-in traits for auth controllers. From there we’ll grab appropriate public methods (which returns to their view blades), and will override view paths.
So we’ll got these (see below) new methods in appropriate controllers.
app\Http\Controllers\User\Auth\ForgotPasswordController.php
public function showLinkRequestForm()
{
return view('user.auth.passwords.email');
}
app\Http\Controllers\User\Auth\LoginController.php
public function showLoginForm()
{
return view('user.auth.login');
}
app\Http\Controllers\User\Auth\RegisterController.php
public function showRegistrationForm()
{
return view('user.auth.register');
}
app\Http\Controllers\User\Auth\ResetPasswordController.php
public function showResetForm(Request $request, $token = null)
{
return view('user.auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
app\Http\Controllers\User\Auth\VerificationController.php
public function show(Request $request)
{
return $request->user()->hasVerifiedEmail()
? redirect($this->redirectPath())
: view('user.auth.verify');
}
Also in “app\Http\Controllers\User\UserController.php” we’ve changed index method (changed view path)
public function index()
{
return view('user.home');
}
Don’t forget “use Illuminate\Http\Request;” at the top, if it needed for ResetPasswordController and VerificationController controllers.
About This 1-st Part:
In this part we’ve created default laravel auth system (login, registration, etc) for users. We’ve replaced our model, views, controllers, routes for separated Users’ & Admins’ staffs.
In the next part I’ll add Admin Authentication System to our app.
Thanks!