Set up Role Based Access Control in Laravel (Updated 2020)

Set up Role Based Access Control in Laravel (Updated 2020)

Editor’s Note: This post was initially published for older versions of Laravel and has been updated to work with the current version ( v6.2+).

Many a time in a web application, you will need to protect specific resources from being accessed by all of your users. While an authentication system ensures that only authorised users can access your application, but implementing precise role-based access control is sometimes necessary. Let me show you how you can implement role based access control in Laravel.

We will not be using any external packages and use Laravel Middlewares to implement this. We will be applying access control for three roles, namely `Admin`, `Agent`, and `Customer` for the User model provided by Laravel.

Set up migrations:

  • Add a new `role` column to our existing user migration:
    Schema::create('users', function (Blueprint $table) {
    	$table->increments('id');
    	$table->string('name');
    	$table->string('email')->unique();
    	$table->string('password');
    	$table->string('role');// the role column
    	$table->rememberToken();
    	$table->timestamps();
    });
    
  • Run the migrations to generate the tables:
    php artisan migrate

    Note: If you have already created the tables before, you may need to run `php artisan migrate:refresh` but be aware that this command will reset all your tables! And then re-run all your migrations.

Customise the registration form:

  • Generate the authentication scaffolding which comes bundled with Laravel.
    php artisan make:auth
  • Now that we have added the role column to our User model we also need to add the input for the roles in our view so add the select tag input to resources/views/auth/register.blade.php‘s registration form.
    <div class="form-group row">
    	<label for="role" class="col-md-4 col-form-label text-md-right">Role</label>
    
    	<div class="col-md-6">
    		<select name="role" class="form-control" >
    			<option value="admin">Admin</option>
    			<option value="agent">Agent</option>
    			<option value="customer">Customer</option>
    		</select> 
    	</div>
    </div>
    

    Set-up_role_based_access_control_in_Laravel-registration_form
    The registration form

Customise User model and RegisterController:

  • Add the role column to `fillable` attribute on the User Model so that we can make use of the `create()` method in Register Controller.
    //User.php
    protected $fillable = [
    	'name', 'email', 'password','role',
    ];
    
  • Now customize RegisterController.php which is in `app/Http/Controllers/Auth` directory to include our role input when creating a new user.
    • Add a validation rule for the role field:
      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',
      		'role' => 'required|in:admin,agent,customer', //validate role input
      	]);
      }
      
    • Add role field to the `create()` method:
      protected function create(array $data)
      {
      	return User::create([
      		'name' => $data['name'],
      		'email' => $data['email'],
      		'password' => bcrypt($data['password']),
      		'role' => $data['role'],
      	]);
      }
      

Now you should be able to register users with different roles. We’ll create at least one user per each role, and we will move on to implementing the access control logic.

Set-up middlewares:

Middleware provides a convenient mechanism for filtering HTTP requests entering our application. For example, Laravel includes an `auth` middleware that verifies the user of your application is logged-in.

  • We will create middlewares for each of our roles.
    php artisan make:middleware Admin
    php artisan make:middleware Agent
    php artisan make:middleware Customer
    
  • Add the following code to respective middlewares which are in app/Http/Middleware folder:
    • Admin.php:
      use Auth; //at the top
      
      function handle($request, Closure $next)
      {
      	if (Auth::check() && Auth::user()->role == 'admin') {
      		return $next($request);
      	}
      	elseif (Auth::check() && Auth::user()->role == 'agent') {
      		return redirect('/agent');
      	}
      	else {
      		return redirect('/customer');
      	}
      }
    • Agent.php:
      use Auth; //at the top
      
      function handle($request, Closure $next)
      {
      	if (Auth::check() && Auth::user()->role == 'agent') {
      		return $next($request);
      	}
      	elseif (Auth::check() && Auth::user()->role == 'customer') {
      		return redirect('/customer');
      	}
      	else {
      		return redirect('/admin');
      	}
      }
    • Customer.php:
      use Auth; //at the top
      
      function handle($request, Closure $next)
      {
      	if (Auth::check() && Auth::user()->role == 'customer') {
      		return $next($request);
      	}
      	elseif (Auth::check() && Auth::user()->role == 'agent') {
      		return redirect('/agent');
      	}
      	else {
      		return redirect('/admin');
      	}
      }
  • Now let’s register our middleware with Laravel. Add the middleware classes to $routeMiddleware property located in app/Http/Kernel.php:
    protected $routeMiddleware = [
        // ...
    	'admin' => 'App\Http\Middleware\Admin',
    	'agent' => 'App\Http\Middleware\Agent',
    	'customer' => 'App\Http\Middleware\Customer',
    ];
    

Now you can apply these middlewares to routes or to the controller itself:

  • web.php:
    Route::get('/admin', function(){
    	echo "Hello Admin";
    })->middleware('admin');
    
    Route::get('/agent', function(){
    	echo "Hello Agent";
    })->middleware('agent');
    
    Route::get('/customer', function(){
    	echo "Hello Customer";
    })->middleware('customer');
  • Or you can specify a middleware in a controller’s constructor, like this:
    public function __construct()
    {
    	$this->middleware('auth');	
        $this->middleware('admin');
    }
    

Redirect User After Log-in:

If you use Laravel’s default login setup, you may want to redirect the user to his role specific page after he logs in. and you can do that by overriding the `redirectTo()` method in your LoginController.php. Make sure you remove the `$redirectTo` property from your `LoginController.php`.

Add this to your `LoginController.php:`

protected function redirectTo( ) {
    if (Auth::check() && Auth::user()->role == 'customer') {
        return('/customer');
    }
    elseif (Auth::check() && Auth::user()->role == 'agent') {
        return('/agent');
    }
    else {
        return('/admin');
    }
}

That’s it; we have successfully implemented role-based access control in Laravel! And you can adapt this method for as many or as few of the roles you might need.

The example project used in this tutorial is available in my GitHub repository.

If you liked this tutorial, then you might be interested in my other tutorials in the Laravel section and be sure to leave any comments or ask any questions you might have in the comment section below!

P.S:

You can also consider making a small donation to support me. Your donation will directly contribute to the running cost of this website and hopefully my college too 🙂

Paypal: https://www.paypal.me/sapneshnaik  |  UPI: [email protected]

4 1 vote
Article Rating
Subscribe
Notify of
guest
63 Comments
oldest
newest most voted
Inline Feedbacks
View all comments
Amratha Tendulkar
Amratha Tendulkar
2 years ago

?

Harry McKinney
Harry McKinney
2 years ago

Wow, this is very cool!

Devlim
Devlim
2 years ago

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?

Žymantas
2 years ago

Nice one 😉

Nikolay Traykov
Nikolay Traykov
2 years ago

How do you know if the Admin is above the Customer in the hierarchy and that everything that applies to the Customer applies to the Admin as well?

Udaiyar
Udaiyar
2 years ago

Nice one.

sagagt505
sagagt505
2 years ago

I have a question? if I want to redirect to different route for different type of user what should i do next? I am newbie for this.

sagagt505
sagagt505
2 years ago
Reply to  sapneshnaik

It’s always redirect to home. 🙁

Vedant Jain
Vedant Jain
1 year ago
Reply to  sagagt505

@sagagt505 This may be because you have not edited the redirectTo() function in LoginController.

himanshu
himanshu
2 years ago

this error is irritating me, please help after login —–
Trying to get property of non-object

D:\xampp\htdocs\authrole\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php

protected function addCookieToResponse($request, $response)
{
$config = config(‘session’);

$response->headers->setCookie(
new Cookie(
‘XSRF-TOKEN’, $request->session()->token(), $this->availableAt(60 * $config[‘lifetime’]),
$config[‘path’], $config[‘domain’], $config[‘secure’], false, false, $config[‘same_site’] ?? null
)
);

return $response;
}

cristian dumitriu
cristian dumitriu
2 years ago
Reply to  himanshu

I have the same error – did you figure it out?

cristian dumitriu
cristian dumitriu
2 years ago
Reply to  himanshu

I found the problem. Check the handle function in the middleware . I have copied the function wrong. Check them and will be solved.

Kajal
Kajal
2 years ago

Very nice, thanks for this tutorial 🙂

Cristian
Cristian
2 years ago

Thank you Naik. I was looking for this.

bila
bila
2 years ago

Route::get(‘/home’, function(){
echo “Hello Admin”;
})->middleware(‘auth’,’admin’,
‘auth’,’client’
);
how to implement this

mohiminul
mohiminul
2 years ago

after login—redirect to home in this proces
is it possible to redirect admin panel/agent or/customer panel after login

Eren Christian
Eren Christian
1 year ago
Reply to  mohiminul

have a same question

Haidar
Haidar
1 year ago

in login page if user selected admin how to redirect user to admin page

Eren Christian
Eren Christian
1 year ago

hi
what to write in protected $redirectTo = ‘/login/checkrole’; in LoginController.php

Anon
Anon
1 year ago

Thank you so much, very helpful!

Simon
1 year ago

Really great stuff! work really well

Vincent Libron
Vincent Libron
1 year ago

say the role field is in another table like
user_type(…){
$table->increment(‘id’);
$table->string(‘type_name’);
}
then the 3 user type is defined in the dbseeder with 1 – admin 2- agent 3-customer
and the user_type table is referenced in the users table.

kiran
kiran
1 year ago

i have used this when i register it goes directly on auth dashbaord which laravel default and when i used LoginController changed then redirect is not working

pradeep
pradeep
1 year ago

i got error when i add

protected function redirectTo( ) in my logincontroller, im using auth.
error : Header may not contain more than a single header, new line detected

elodie compain
elodie compain
1 year ago
Reply to  pradeep

me either!

kumar
1 year ago
Reply to  pradeep

protected function redirectTo( ) {
if (Auth::check() && Auth::user()->role == ‘customer’) {
return ‘/customer’;
}
elseif (Auth::check() && Auth::user()->role == ‘vendor’) {
return ‘/vendor’;
}
else {
return ‘/admin’;
}
}

Mine worked when i removed redirect from return redirect
added use Auth; at the top

Dex
Dex
1 year ago

I have a problem. After registering new account, it redirects me to home which is in HomeController. How can I redirect registered user according to their roles. Thanks

seng ly
seng ly
1 year ago

After i am login it’s redirect to home page but it is not redirect to Admin, Agent,Customer page. Please help me Thanks!!!

Sagar Basnet
Sagar Basnet
1 year ago

i am having a error as:ErrorException thrown with message “Header may not contain more than a single header, new line detected” Stacktrace:
#4 ErrorException in E:\xamp\htdocs\TMS\vendor\symfony\http-foundation\Response.php:341
#3 header in E:\xamp\htdocs\TMS\vendor\symfony\http-foundation\Response.php:341
#2 Symfony\Component\HttpFoundation\Response:sendHeaders in E:\xamp\htdocs\TMS\vendor\symfony\http-foundation\Response.php:375
#1 Symfony\Component\HttpFoundation\Response:send in E:\xamp\htdocs\TMS\public\index.php:58
#0 require_once in E:\xamp\htdocs\TMS\server.php:21 help me out from this

Praful Dhabekar
Praful Dhabekar
1 year ago
Reply to  Sagar Basnet

I think this is late reply for this question but if someone has similar problem in LoginController they can use
return ‘/customer’;
instead of this return redirect(‘/customer’);

max
max
1 year ago

this will not work if you want be agent and admin

Samara Ferreira
Samara Ferreira
1 year ago

thank you very much for this tutorial, all I was needing was him. Congrats

Sugizo
Sugizo
1 year ago

Thanks bro… Worked in my case clear and clean

Kay
Kay
1 year ago

This tutorial is very straightforward and I must say it has helped me in this school project that I am working on.
I am using the latest Laravel 5.7 so I had to make some few adjustments especially in the LoginController.php. I used protected function authenticated(Request $request, $user) instead of protected function redirectTo( ) .
But it worked perfectly. Thanks very much

Ray Bennett
Ray Bennett
1 year ago
Reply to  Kay

Sapnesh – this is great – thank you! Hi Kay – Can you elaborate on what you did in 5.7 in the LoginController. After I added everything I continued to get this error: “Method App\Http\Controllers\Auth\LoginController::login does not exist.”

Kay
Kay
1 year ago
Reply to  Ray Bennett

In the LoginController i have:

protected function authenticated(Request $request, $user)

instead of:

protected function redirectTo( )

Kay
Kay
1 year ago
Reply to  Ray Bennett

Note that i also applied the middlewares to the controller itself. Example in my App\Http\Controllers\AdminController.php
i added:
public function __construct()
{
$this->middleware(‘auth’);
$this->middleware(‘admin’);
}

And in the routes\web.php
i didnt apply the middleware as stated in this tutorial.

FROM:
Route::get(‘/admin’, function(){
echo “Hello Admin”;
})->middleware(‘auth’,’admin’);

TO:
Route::get(‘/admin’, function(){
return view(‘admin’);
});

Ray Bennett
Ray Bennett
1 year ago
Reply to  Kay

Thank you, Kay. I appreciate the replies!!!

kumar
1 year ago
Reply to  Kay

You Really saved me. Thanks a lot dear

Jin Min
Jin Min
1 year ago

Great help. Thank you for your post

John
John
1 year ago

Thank you very much.

vdem
vdem
1 year ago

There are built-in features in Laravel for authorization and access control, they are called Gates and Policies, more there: https://laravel.com/docs/5.7/authorization

Dhenn
1 year ago

Did not work on Laravel 5.7 especially on Login controller and routes, how to fix this?

Class ‘App\Http\Controllers\Auth\Auth’ not found

Praful Dhabekar
Praful Dhabekar
1 year ago
Reply to  Dhenn

add this line at the top of your code.
use Auth;

Praful Dhabekar
Praful Dhabekar
1 year ago

if (Auth::check() && Auth::user()->role == ‘admin’) {
return $next($request);
}
In this code you used User table I presume but already I’ve a table called user_registrations. So my question is how I can use that table in this code.?

Mustafa
Mustafa
1 year ago

Fatal error: Cannot redeclare App\Http\Kernel::$routeMiddleware in C:\xampp\htdocs\computer\app\Http\Kernel.php on line 80

lee
lee
1 year ago

ErrorException (E_WARNING)
Header may not contain more than a single header, new line detected

getting this error when logged in

Anirban Deb
Anirban Deb
1 year ago

but why i can not use this role in blade, like @if(Auth::user()->role == ‘Admin’)
Feature for Admin
@endif
since the role is inside user table i should be able to use it right

AndrewNob
5 months ago

У меня сообщение. Так много не честных компаний развелось выдающих займы онлайн, что нельзя встречать неоплачиваемый сервис подбора займов без регистрации и списывания денег следовать подбора. Давеча наткнулся для правильный сайте где дают круглосуточные займы.
Беру займы на карту онлайн только здесь
займы онлайн