Roles and permission in laravel are used to provide roles based authentication and in this post we will learn simplest wat to use roles and permission in laravel. In our application we want features and modules on basis of roles or permissions so that we can restrict users to access the content according to their accessibility.
To accomplish the users based permission and roles we will use spatie/laravel-permission
package. This packages covers all aspects for roles and permission like assigning permission directly to user, roles to user, multiple role, sync, blade directives etc.
In this post we will take a simple example in which we will create a tables, migration and seeder then assign the roles and permission. we will create 3 roles as follow
- Writer
- Admin
- Super Admin
Writer will be able to add and edit articles, Admin will be able to publish and un publish articles and last Super Admin will be able to perform all activities. For super admin we will create a gate so super admin will be able to access everything without assigning the permission.
This example will work in version of laravel 5, laravel 6, laravel 7, laravel 7 and laravel 9 but you need to change the version of spatie/laravel-permission
package according to your laravel version.
Step 1: Create a laravel project
First step is to create the Laravel project using composer command or you can also read the How to install laravel 8 ? and Laravel artisan command to generate controllers, Model, Components and Migrations
composer create-project laravel/laravel rolespermission
Step 2: Configure database
Next step is to configure the database for our project, table and data. So open .env or if file not exist then rename .env.example file to .env
file in root folder and change below details
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rolespermission
DB_USERNAME=root
DB_PASSWORD=
Step 3: Configure Roles and Permissions
First of all add the the package as follow
composer require spatie/laravel-permission
publish the migration and the config/permission.php
config file with:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
check more info here: Installation
Output:
INFO Publishing assets. Copying file [vendor/spatie/laravel-permission/config/permission.php] to [config/permission.php] DONE Copying file [vendor/spatie/laravel-permission/database/migrations/create_permission_tables.php.stub] to [database/migrations/2022_08_20_124256_create_permission_tables.php] DONE
Clear the caches first
php artisan optimize:clear
Output:
INFO Clearing cached bootstrap files. events ............................................................ 1ms DONE views ............................................................. 0ms DONE cache ............................................................. 1ms DONE route ............................................................. 0ms DONE config ............................................................ 0ms DONE compiled .......................................................... 0ms DONE
Run migrations
php artisan migrate
Output:
INFO Preparing database. Creating migration table ......................................... 35ms DONE INFO Running migrations. 2014_10_12_000000_create_users_table ............................. 49ms DONE 2014_10_12_100000_create_password_resets_table ................... 46ms DONE 2019_08_19_000000_create_failed_jobs_table ....................... 49ms DONE 2019_12_14_000001_create_personal_access_tokens_table ............ 73ms DONE 2022_08_20_124256_create_permission_tables ...................... 515ms DONE
Create Seeders for Roles, Permissions and Users
Here we will create three users writer, admin and superadmin
with roles and permission.
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;
class RolesPermissionSeeder extends Seeder
{
/**
* Create the initial roles and permissions.
*
* @return void
*/
public function run()
{
// Reset cached roles and permissions
app()[PermissionRegistrar::class]->forgetCachedPermissions();
// create permissions
Permission::create(['name' => 'articles.view']);
Permission::create(['name' => 'articles.edit']);
Permission::create(['name' => 'articles.delete']);
Permission::create(['name' => 'articles.publish']);
Permission::create(['name' => 'articles.unpublish']);
// create roles and assign existing permissions
$role1 = Role::create(['name' => 'writer']);
$role1->givePermissionTo('articles.view');
$role1->givePermissionTo('articles.edit');
$role1->givePermissionTo('articles.delete');
$role2 = Role::create(['name' => 'admin']);
$role2->givePermissionTo('articles.view');
$role2->givePermissionTo('articles.publish');
$role2->givePermissionTo('articles.unpublish');
$role3 = Role::create(['name' => 'SuperAdmin']);
// gets all permissions via Gate::before rule; see AuthServiceProvider
// create demo users
$user = \App\Models\User::factory()->create([
'name' => 'Example User Writer',
'email' => 'test@example.com',
]);
$user->assignRole($role1);
$user = \App\Models\User::factory()->create([
'name' => 'Example Admin User',
'email' => 'admin@example.com',
]);
$user->assignRole($role2);
$user = \App\Models\User::factory()->create([
'name' => 'Example Super-Admin User',
'email' => 'superadmin@example.com',
]);
$user->assignRole($role3);
}
}
As you can see we have created five permissions articles.view
, articles.edit
, articles.delete
, articles.publish
and articles.unpublish
.
Then we have assigned articles.view
, articles.edit
, articles.delete
to writer role. articles.publish
and articles.unpublish
to Admin role and then then we assigned all roles to users.
Now run seeders as follow
php artisan db:seed --class=RolesPermissionSeeder
As we know superadmin
can access everything so let’s create a gate so super admin role can access everything in the system as follow
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// Implicitly grant "SuperAdmin" role all permission checks using can()
Gate::before(function ($user, $ability) {
if ($user->hasRole('SuperAdmin')) {
return true;
}
});
}
}
Step 4 : Create a controller
Next, Create the a controller and add the necessary imports and class. You can create by Laravel artisan or manually.
php artisan make:controller ArticleController
Now, add the controller logic for roles and permission
<?php
namespace App\Http\Controllers;
use App\Models\Article;
use App\Models\User;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
}
public function loginAs(Request $request, $userid)
{
if ($userid > 0) {
\Auth::guard()->login(User::find($userid));
} else {
\Auth::guard()->logout();
}
return redirect("show-articles");
}
public function show()
{
$isLoggedin = false;
$user = null;
$articles = null;
if (\Auth::guard()->check()) {
$isLoggedin = true;
$user = \Auth::guard()->user();
// dd($user);
$articles = Article::paginate(10);
}
return view('articles', [
"isLoggedin" => $isLoggedin,
"user" => $user,
"articles" => $articles
]);
}
public function edit(Request $request, $userid)
{
if ($request->user()->can("articles.edit")) {
return "success";
} else {
return "Do not have permissions";
}
}
public function delete(Request $request, $userid)
{
if ($request->user()->can("articles.delete")) {
return "success";
} else {
return "Do not have permissions";
}
}
}
Step 5 : Create the views
Here in this step we will create a view as follow
resources/views/rolepermission/articles.blade.php
– To list all articles
So here is the code for resources/views/rolepermission/articles.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simplest Laravel User Roles and Permission - Readerstacks </title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body class="antialiased">
<div class="container">
<!-- main app container -->
<div class="readersack">
<div class="container">
<div class="row">
<div class="col-md-12 ">
<h3>Simplest Laravel User Roles and Permission - Readerstacks</h3>
<div class="login-status">
@if($isLoggedin)
<h2 style='color:blue'>Logged in as {{$user->email}}</h2>
@endif
<div>
<a href="{{url('login-user/3')}}">Login as SuperAdmin</a> |
<a href="{{url('login-user/2')}}">Login as Admin</a> |
<a href="{{url('login-user/1')}}">Login as Writer</a> |
<a href="{{url('login-user/0')}}">Logout</a>
</div>
</div>
@if($isLoggedin && $user->can("articles.view"))
<div id="pagination_data">
<table class="table table-striped table-dark table-bordered">
<tr>
<th>Sr No.</th>
<th>Title</th>
<th>Body</th>
<th>Date</th>
<th>Action</th>
</tr>
@foreach($articles as $article)
<tr>
<td>{{$article->id}}</td>
<td>{{$article->title}}</td>
<td>{{substr($article->body,0,50)}}</td>
<td>{{$article->created_at}}</td>
<td>
@can(["articles.publish","articles.unpublish"])
<a href="" class="btn btn-success">Publish</a>
@endcan
@can("articles.edit")
<a href="{{route('articles.edit',$article->id) }}" class="btn btn-success">Edit</a>
@endcan
@can("articles.delete")
<form action="{{ route('articles.destroy',$article->id) }}" method="Post">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger">Delete</button>
</form>
@endcan
</td>
</tr>
@endforeach
</table>
<div id="pagination">
{{ $articles->links() }}
</div>
</div>
@else
<p style='color:red'>You do not have permission to View Articles</p>
@endif
</div>
</div>
</div>
</div>
<!-- credits -->
<div class="text-center">
<p>
<a href="#" target="_top">Simplest Laravel User Roles and Permission
</a>
</p>
<p>
<a href="https://readerstacks.com" target="_top">readerstacks.com</a>
</p>
</div>
</div>
</body>
</html>
@can
– is a blade directive used to check the assigned permissions.
Step 6 : Create Route
Last and final step is to create the route for our roles and permission controller to serve the role based users permission
<?php
use Illuminate\Support\Facades\Route;
Route::get('/show-articles', "\App\Http\Controllers\ArticleController@show" );
Route::get('/login-user/{id}', "\App\Http\Controllers\ArticleController@loginAs" );
Route::get('/edit/{id}', "\App\Http\Controllers\ArticleController@edit" )->name("articles.edit");
Route::post('/delete/{id}', "\App\Http\Controllers\ArticleController@delete" )->name("articles.destroy");