DEV Community

loading...

Multiple role-based authentication in Laravel

kaperskyguru profile image Solomon Eseme Originally published at masteringbackend.com on ・5 min read

Hey guys, in this article, am going to show you how toimplement multiple role-based authentication in Laravel even if you have many different users and multiple dashboards respectively.

Before we delve into achieving that, let me breakdown my scenarios or problems I was facing in a project I was working for a company, that made me spend almost two weeks trying to figure it out.

In this project, I was presented with six (6) different users and their respective dashboards too, the users were as follows viz:

  1. Super Admin
  2. Admin
  3. Players
  4. Teams
  5. Academics
  6. Scouts

So, the problem was to redirect the users to their respective dashboards on successful logins and restrict access to any other dashboards even if they typed in the URL to or try to access the other dashboard, it should redirect them back to their default dashboard.

As I read through many blog posts, video tutorials, and questionings which was great, I discovered that whenever I successfully implement a solution, I will always discover a fault during security test/checks such as “too many redirect errors” or enabling a logged-in player to access a scout dashboard, etc.

I also discovered many solutions such as the use of guards, middleware, etc. which helped tremendously.

GETTING STARTED

Enough of the housekeeping things, let me move down to how I successfully implement multiple role-based authentications in Laravel and save myself two weeks of sleepless nights.

We will start by installing a fresh new Laravel project, you can skip these steps if you are comfortable with it.

CREATING A FRESH LARAVEL

Type in the following commands in your projects folder assuming you have php 7.* and composer installed. You can check here to learn how to install Laravel.

composer create-project --prefer-dist laravel/laravel MultiAuth

S ETTING UP YOUR DATABASE AND .ENV FILE

The next step is to set up your database migrations and configuring your environment file. Go to your phpMyAdmin and create a database.

Open your user migration file and add the following columns

After that, open your .env file and pass in your database credentials

Run your migrations

php artisan migrate

You can set up database seeders to fill your database with data or you can add it manually, whichever way is good, or you can simply use my code examples since I have set up a database seeder already just for this example.

SETTING UP USER AUTH.

After setting up your database and running migrations, the next step is to use Laravel default authentication which is just fine for our example, Thanks to Laravel teams.

By just running:

php artisan make:auth

You should successfully set up a complete user registration and login system out of the box, now visit your newly created Laravel project by typing.

php artisan serve

And typing 127.0.0.1:8000 in the browser. At this stage, you can decide to seed six (6) different users with corresponding user roles or manually insert them into the database.

So, our user role is going to be numerical as follows:

  1. Super Admin
  2. Admin
  3. Player
  4. Team
  5. Academic
  6. Scout

After properly seeding the dummy user data, if you are happy with it, let's move to the next step.

CREATING DASHBOARD CONTROLLERS

The next step will be to create different dashboard controllers for different users. Type

php artisan make:controller AdminController

php artisan make:controller PlayerController

Repeat until you complete the six (6) dashboards.

CREATING MIDDLEWARES

After creating the different controllers, the next step is to create the different middleware corresponding to the different user roles. TYPE

php artisan make:middleware Admin

php artisan make:middleware Player

Repeat until you complete the six (6) middlewares.

After creating the middleware, now go into the kernel.php file under the $routeMiddleware array and register them.

After registering the middleware appropriately, the next step is assigning the middleware to the different controllers or routes you want to protect.

SETTING UP VIEWS AND ROUTES

Go to your views folder and create a different view dashboard. Remember the dashboard files can be inside different folders, it doesn’t matter, just route them correctly inside your controllers.

View Folder in a laravel project
Different user dashboards

Inside each of the dashboards, I added a dummy text, just to demonstrate.

After creating the view, go to web.php under the routes folder and set up the different routes to access the different dashboards.

Now, here is the interesting part, in my example or project, I prefer assigning the middleware to the routes instead of adding it into the Controller constructors.

EDITING THE MIDDLEWARE

After registering and assigning the middleware to the routes or controllers, let edit the contents of each of the middlewares. So, inside the handle method, check if the user is Authenticated and redirect according to the user role to the different dashboards.

EDITING THE LOGIN AND REGISTER CONTROLLER

After a successful login, you need to redirect the user to the appropriate dashboard based on the user role.

You can do the same with Register Controller or you can simply redirect users to the verify page and after verification, you can redirect to the dashboard or login page again depending on your project.

CONCLUSIONS

Wow!!! Congratulations, that was a long read and code typing, you can watch the video here.

So far, the problem we have solved is preventing a logged-in user from accessing other users’ dashboards and also preventing “too many redirect errors” when working with guards wrongly.

we understand that there are many ways to kill a rat, we want to hear your thoughts and best practices on how to solve this same issue, if you have encountered it before, how did you solve it, lets hear it in the comment section below and we will update this post accordingly.

You can get the full source code here

If you enjoy this post make sure you share it with your friends and subscribe to my growing channel.

If you are interested in backend development (or you’re internet enthusiast) both (Mobile | Web | Desktop) subscribe to my [_Youtube channel](http://bit.ly/multimegaschool), we will be posting a collection of help full tutorials and guides like this one for artisans_

The post Multiple role-based authentication in Laravel appeared first on Masteringbackend.

Discussion (29)

pic
Editor guide
Collapse
martin_betz profile image
Martin Betz

And here's another refactor to make it even conciser and easier to read and change. It is using a lookup array to isolate changes (just add a new item to the array for a new role) and have one execution path (one redirect line instead of 5).

public function handle($request, Closure $next)
    {
        if (!Auth::check()) {
            return redirect()->route('login');
        }

        if (Auth::user()->role == 3) {
            return $next($request);
        }

        $destinations = [
            1 => 'superadmin',
            2 => 'admin',
            4 => 'team',
            5 => 'academy',
            6 => 'scout',
        ];

        return redirect(route($destinations[Auth()::user()->role]));
    }
Enter fullscreen mode Exit fullscreen mode
Collapse
kaperskyguru profile image
Solomon Eseme Author

I'm Having errors after implementing this.
I logged in as academy then try to visit the admin dashboard by typing the route to it in the browser and i got this -> "Call to undefined method Illuminate\Auth\AuthManager::user()"

Collapse
computermaverick profile image
⚓Timmy Iwoni ⚓

In Martin's implementation there's a typo of the parenthesis when calling the Auth facade... So instead of Auth()::user()->role, it should be Auth::user()->role

Thread Thread
kaperskyguru profile image
Solomon Eseme Author

Oh that's true.. I will fix that..

Collapse
martin_betz profile image
Martin Betz

I'll replicate it soon, probably I just have a typo somewhere.

Thread Thread
kaperskyguru profile image
Solomon Eseme Author

Sure. I will be expecting.

Collapse
baronsindo profile image
𝙹𝚒𝚋𝚛āʾī𝚕 ⚡

a comment that make me awkwardly happy

Collapse
kaperskyguru profile image
Solomon Eseme Author

Wow.. it's getting more clean and clear.. Thanks for the update.

Collapse
martin_betz profile image
Martin Betz

May I propose a refactor for the handle method? You could save some duplications by flipping the logic. If you first ask for if the user is not logged in, redirect to login you catch this case once and can skip it for everything that follows. Also, instead of elseelse, you can simply use ifif. If a case proves true, you return something and the function stops, so you do not need an else. This reduces cognitive load.

public function handle($request, Closure $next)
{
    if (! Auth::check()) {
        return redirect()->route('login');
    }

    if (Auth::user()->role == 1) {
        return redirect()->route('superadmin');
    }

    if (Auth::user()->role == 5) {
        return redirect()->route('academy');
    }

    if (Auth::user()->role == 6) {
        return redirect()->route('scout');
    }

    if (Auth::user()->role == 4) {
        return redirect()->route('team');
    }

    if (Auth::user()->role == 3) {
        return $next($request); 
    }

    if (Auth::user()->role == 2) {
        return redirect()->route('admin');
    }
}
Collapse
picwellwisher12pk profile image
Amir Hameed

What about switch statement?

Collapse
martin_betz profile image
Martin Betz

Yes, switch would cut some duplicate lines. I would still propose the lookup array pattern as recommended in this extra comment as it is a lot easier to add and cut arguments and is super easy to read.

Thread Thread
picwellwisher12pk profile image
Amir Hameed

These if statements could also be one-liners to save some more characters and space.

Thread Thread
martin_betz profile image
Martin Betz

Yes, but there still would be lots of repetitions even in short-form. Maybe I can write an own article soon about possible refactorings so that people can learn and compare. The original poster went with the simple if solution but there are multiple ways to make it shorter and easier to maintain.

Thread Thread
picwellwisher12pk profile image
Amir Hameed

Indeed.
Tell me where can I start a new discussion?

Thread Thread
martin_betz profile image
Martin Betz

Just put a comment on the root of this article: dev.to/kaperskyguru/multiple-role-...

Collapse
kaperskyguru profile image
Solomon Eseme Author

This is great, thanks for your contribution, I will refactor immediately.

Collapse
kaperskyguru profile image
Collapse
omaresmael profile image
omaresmael

It was a beautiful tutorial, there is a routing refactor must be done tho, in order to function properly in laravel 8

Route::get('/player', [PlayerController::class,'index'])->name('player')->middleware('player');

instead of

Route::get('/player', 'PlayerController@index')->name('player')->middleware('player');

there are other ways to solve this problem but that just my favorite one

Collapse
vncdigitalservices profile image
VNC Digital Services Pvt Ltd

This work for page level and route level access control. Is there any guide for page element access control? Such as hide delete button for non-admin, disabled edit capability for certain form field access control?

Collapse
kaperskyguru profile image
Solomon Eseme Author

You can use action based control, like Spartia library for such.
github.com/spatie/laravel-permission

Collapse
raviameriya profile image
Ravi K. Ameriya

created role middleware but getting an error

error: Attempt to read property "role" on null

middleware function below as :
public function handle(Request $request, Closure $next)
{
if (!Auth::check()) {

        return redirect()->route('login');
    }

    if (Auth::check() && Auth::user()->role == 1) {

        return $next($request);
        //return redirect()->route('dashboardShow');
    }

    if (Auth::check() && Auth::user()->role == 2) {


        return $next($request);
        //dd('user');
    }

    abort(404);  // for other user throw 404 error

}
Enter fullscreen mode Exit fullscreen mode
Collapse
rvp04 profile image
VP

i used your code and i am getting this error

127.0.0.1 redirected you too many times.

Collapse
boypanjaitan16 profile image
Boy Panjaitan

How if the user have multiple account with different roles,but with the same credentials ? I assumed this nice guide not covered it yet :)

Collapse
mrdionjr profile image
Salomon Dion

In that case, create a separate table for roles and permissions (spatie/laravel-permission can help). Then, create the permissions and roles and assign permissions to roles. I would recommend as best practice to rely mainly on permissions in your applications as differents roles may have common permissions. Now, when a user is created assign him a role, and rely on this first role for redirect ($user->roles()->id). You can have a menu where he can switch to another dashboard based on his roles. Hope it helps.

Collapse
kaperskyguru profile image
Solomon Eseme Author

Yes the article didn't cover that. But I will suggest you use OTP to implement such scenerios.

Collapse
estern_winluck profile image
Estern Winluck

Great!
I wish to know how to handle when a user has multiple roles ie. superadmin and admin

Collapse
ryan1 profile image
ryan

Nice, this was a great tutorial!

Collapse
agusmaulanaok profile image
agusmaulanaok

how if use JWT,tq

Collapse
kaperskyguru profile image
Solomon Eseme Author

Please give a more clear scenerios for your issues.