Simple Laravel 10 User Roles and Permissions
In this tutorial, we will learn about Laravel user roles and permissions by developing a complete Laravel 10 User Roles and Permissions application with easy and step by step guide.
We will use Spatie a Laravel permission package that will help us to create a Laravel ACL (Access Control List) to manage user roles and permissions.
It is very essential to learn about Laravel 10 Spatie user roles and permissions.
In this example, we will use the Laravel 10 with the latest Bootstrap 5.3 version.
Although, there are several ways to implement Laravel 10 ACL for user roles and permissions. You can either use a Laravel package or can write code for entire ACL concept.
Writing entire user roles and permissions is quite time consuming compared to a package. Therefore, we will use Laravel Spatie permission package for this example.
A Laravel Spatie permission package provides a convenient way to assign a role to a user or permission to a user and assign permission to roles.
What is Role and Permission?
In the web application development, roles and permissions are most common terms.
A permission is simply having the rights to access something. For example: A user having an access to add new product in your application.
A role is nothing but just a collection of permissions that can be assigned to user.
It is recommended to assign a role to a user instead of direct permissions. However, you can assign permissions as well if you need.
Readers Also Read: Laravel 10 REST API using Passport Authentication
Tutorial Example Roles and Permissions
In this tutorial, we will create the default following roles in our Laravel seeder:
- Super Admin
- Admin
- Product Manager
You can create more roles as per your need via Super Admin user.
And add the following permissions and assign the relevant permissions to relevant roles in the seeder:
- create-role
- edit-role
- delete-role
- create-user
- edit-user
- delete-user
- create-product
- edit-product
- delete-product
From serial number 4 to 9 permissions will be assigned to Admin role and 7 to 9 permissions will be assigned to Product Manager.
And we will not assign any permission to Super Admin because we will handle Super Admin using alternate and Spatie recommended method.
We will use Laravel’s Gate::before() method in AuthServiceProvider to grant access to all permissions to Super Admin.
Prerequisite of Laravel 10 Roles and Permissions
Before diving into Laravel user roles and permissions, you must be aware of how to create Laravel CRUD application and how to create Laravel custom user registration and login.
As we will perform Laravel CRUD operations to Manage Roles, Users and Products.
Application Flow
We will create a products table that will store all products details which are product name and description.
A product CRUD enable us to create new product information, view product, edit/update product and delete products from database.
We will also add feature to add role, view role, update and delete role in the tables generated by Spatie package.
Users default table is available in Laravel, we will add new user and assign role to that user, view user, update user and delete user.
In this tutorial, only Super Admin can manage role. Super Admin create new role and assign available permissions to that specific role.
Admin can manage users and products while Product Manager can only manage products.
Application Screenshots
Following are the screenshots of the Laravel user roles and permissions application.
1. Role Management Screenshots:
Role List Page
Add New Role Page
Edit Role Page
Show Role Page
2. User Management Screenshots:
User List Page
Add New User Page
Edit User Page
Show User Page
3. Product Management Screenshots:
Product List Page
Add New Product Page
Edit Product Page
Show Product Page
So now without further delay, lets start developing a simple Laravel 10 user roles and permissions application with Spatie package example.
Steps to Create Laravel 10 User Roles and Permissions App
Follow the below simple and easy step by step guide to create a Laravel roles and permission application.
- Install Laravel 10 App
- Install Spatie Laravel Permission Package
- Add Role and Permission Middleware
- Create a Product Model with Migration, Resource Controller and Form Requests
- Update Migration and Model of Product
- Add Spatie Traits in User Model
- Create Role, Permission and Super Admin Seeder
- Configure Database Credentials
- Migrate Tables and Seed to Database
- Defining a Super Admin in AuthServiceProvider
- Enable Bootstrap 5 in AppServiceProvider
- Laravel Bootstrap Auth Scaffolding – User Register and Login
- Define Role, User and Product Resource Routes
- Create Role and User Resource Controllers
- Update Role, User and Product Controllers
- Make Role and User Form Requests
- Update Role, User and Product Store and Update Form Requests
- Create Role, User and Product Resource Blade View Files
- Update Application Layout and Home Blade View Files
- Run Laravel Development Server
1. Install Laravel 10 App
Install the Laravel 10 app with name laravel-10-roles by running the below command on your terminal window or command prompt.
composer create-project --prefer-dist laravel/laravel:^10 laravel-10-roles
And then navigate to laravel-10-roles directory by running the below command.
cd laravel-10-roles
2. Install Spatie Laravel Permission Package
Now install the Spatie Laravel permission package by running the below command using composer.
composer require spatie/laravel-permission
After installation of the Spatie package, we will need to publish the config and database migration files using the below command.
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
This will create a migration file with name like YYYY_MM_DD_TIMESTAMP_create_permission_tables.php and it will create 5 tables mentioned below that will hold roles and permissions related information.
- roles – This table will store the name of all the roles of your application.
- permissions – This table will store the name of all the permissions of your application.
- role_has_permissions – This table will store all the permissions that are assigned to each role.
- model_has_roles – This table will store roles that are assigned to each model.
- model_has_permissions – This table will store permissions that are assigned to each model. For example a User model.
3. Add Role and Permission Middleware
In this tutorial example, we are using Laravel-permission v6, now we need to add role and permission middleware in app/Http/Kernel.php file as given below.
protected $middlewareAliases = [
....
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
];
For previous versions of Laravel-permission, go through the official documentation, as there is a slightly change in middleware aliases.
In Laravel-permission v5, you will need to write Middlewares, instead of Middleware in the above three middlewares.
4. Create a Product Model with Migration, Resource Controller and Form Requests
Following command will create a product model with migration, resource controller and form requests to validate input data.
php artisan make:model Product -mcr --requests
- –m flag is for migration
- –cr flag is for a resource controller
- –requests flag for form requests
5. Update Migration and Model of Product
Now, in this step we will need to update product migration, just go to the database\migrations directory and our product migration file is available there.
YYYY_MM_DD_TIMESTAMP_create_products_table.php
Open this product migration file and paste the following code in it.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
Now go to the app\Models\Product.php and update the product model file.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description'
];
}
6. Add Spatie Traits in User Model
Simply go to the app\Models\User.php and update the user model file.
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
7. Create Role, Permission and Super Admin Seeder
Run the below commands on terminal to create role, permission and Super Admin seeder. You can run all three commands together as well.
php artisan make:seeder PermissionSeeder
php artisan make:seeder RoleSeeder
php artisan make:seeder SuperAdminSeeder
Now go to database\seeders and update each seeder file with the following code.
PermissionSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Spatie\Permission\Models\Permission;
class PermissionSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$permissions = [
'create-role',
'edit-role',
'delete-role',
'create-user',
'edit-user',
'delete-user',
'create-product',
'edit-product',
'delete-product'
];
// Looping and Inserting Array's Permissions into Permission Table
foreach ($permissions as $permission) {
Permission::create(['name' => $permission]);
}
}
}
RoleSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class RoleSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Role::create(['name' => 'Super Admin']);
$admin = Role::create(['name' => 'Admin']);
$productManager = Role::create(['name' => 'Product Manager']);
$admin->givePermissionTo([
'create-user',
'edit-user',
'delete-user',
'create-product',
'edit-product',
'delete-product'
]);
$productManager->givePermissionTo([
'create-product',
'edit-product',
'delete-product'
]);
}
}
SuperAdminSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class SuperAdminSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// Creating Super Admin User
$superAdmin = User::create([
'name' => 'Javed Ur Rehman',
'email' => '[email protected]',
'password' => Hash::make('javed1234')
]);
$superAdmin->assignRole('Super Admin');
// Creating Admin User
$admin = User::create([
'name' => 'Syed Ahsan Kamal',
'email' => '[email protected]',
'password' => Hash::make('ahsan1234')
]);
$admin->assignRole('Admin');
// Creating Product Manager User
$productManager = User::create([
'name' => 'Abdul Muqeet',
'email' => '[email protected]',
'password' => Hash::make('muqeet1234')
]);
$productManager->assignRole('Product Manager');
}
}
The above Super Admin Seeder file also creating Admin and Product Manager users. However, you can remove them if you wish. We recommend keep them so that you can test the application with each user of different roles.
Now open DatabaseSeeder.php file and paste the following code in it.
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
$this->call([
PermissionSeeder::class,
RoleSeeder::class,
SuperAdminSeeder::class,
]);
}
}
8. Configure Database Credentials
Now in this step, we need to update database credentials. Simply update the .env file which is available on the root directory.
Open the .env file and update with your own database credentials.
Database Credentials:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_db_name
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password
9. Migrate Tables and Seed to Database
Run the below command in your terminal/command prompt to migrate all migrations tables including products, roles and permissions tables along with seed to database.
php artisan migrate:fresh --seed
10. Defining a Super Admin in AuthServiceProvider
Go to app\Providers\AuthServiceProvider.php and update the following code in it.
<?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 = [
//
];
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
Gate::before(function ($user, $ability) {
return $user->hasRole('Super Admin') ? true : null;
});
}
}
11. Enable Bootstrap 5 in AppServiceProvider
Go to app\Providers\AppServiceProvider.php and update the following code in it.
<?php
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::useBootstrapFive();
}
}
12. Laravel Bootstrap Auth Scaffolding – User Register and Login
Now we need to create Laravel bootstrap auth scaffolding for user register and login.
First install Laravel UI package, using below command.
composer require laravel/ui
Then to create bootstrap auth scaffolding use the below command.
php artisan ui bootstrap --auth
Now, install the node modules by running the below command.
npm install
And then build the assets by running the below command.
npm run build
13. Define Role, User and Product Resource Routes
Just copy and paste the below code in your routes/web.php file.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\RoleController;
use App\Http\Controllers\UserController;
use App\Http\Controllers\ProductController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::resources([
'roles' => RoleController::class,
'users' => UserController::class,
'products' => ProductController::class,
]);
14. Create Role and User Resource Controllers
Run the below commands to create role and user resource controllers.
php artisan make:controller RoleController --resource
php artisan make:controller UserController --resource
15. Update Role, User and Product Controllers
Just go to the app\Http\Controllers and update the following files.
RoleController.php
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreRoleRequest;
use App\Http\Requests\UpdateRoleRequest;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use DB;
class RoleController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('permission:create-role|edit-role|delete-role', ['only' => ['index','show']]);
$this->middleware('permission:create-role', ['only' => ['create','store']]);
$this->middleware('permission:edit-role', ['only' => ['edit','update']]);
$this->middleware('permission:delete-role', ['only' => ['destroy']]);
}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('roles.index', [
'roles' => Role::orderBy('id','DESC')->paginate(3)
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('roles.create', [
'permissions' => Permission::get()
]);
}
/**
* Store a newly created resource in storage.
*/
public function store(StoreRoleRequest $request): RedirectResponse
{
$role = Role::create(['name' => $request->name]);
$permissions = Permission::whereIn('id', $request->permissions)->get(['name'])->toArray();
$role->syncPermissions($permissions);
return redirect()->route('roles.index')
->withSuccess('New role is added successfully.');
}
/**
* Display the specified resource.
*/
public function show(Role $role): View
{
$rolePermissions = Permission::join("role_has_permissions","permission_id","=","id")
->where("role_id",$role->id)
->select('name')
->get();
return view('roles.show', [
'role' => $role,
'rolePermissions' => $rolePermissions
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Role $role): View
{
if($role->name=='Super Admin'){
abort(403, 'SUPER ADMIN ROLE CAN NOT BE EDITED');
}
$rolePermissions = DB::table("role_has_permissions")->where("role_id",$role->id)
->pluck('permission_id')
->all();
return view('roles.edit', [
'role' => $role,
'permissions' => Permission::get(),
'rolePermissions' => $rolePermissions
]);
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateRoleRequest $request, Role $role): RedirectResponse
{
$input = $request->only('name');
$role->update($input);
$permissions = Permission::whereIn('id', $request->permissions)->get(['name'])->toArray();
$role->syncPermissions($permissions);
return redirect()->back()
->withSuccess('Role is updated successfully.');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Role $role): RedirectResponse
{
if($role->name=='Super Admin'){
abort(403, 'SUPER ADMIN ROLE CAN NOT BE DELETED');
}
if(auth()->user()->hasRole($role->name)){
abort(403, 'CAN NOT DELETE SELF ASSIGNED ROLE');
}
$role->delete();
return redirect()->route('roles.index')
->withSuccess('Role is deleted successfully.');
}
}
UserController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
/**
* Instantiate a new UserController instance.
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('permission:create-user|edit-user|delete-user', ['only' => ['index','show']]);
$this->middleware('permission:create-user', ['only' => ['create','store']]);
$this->middleware('permission:edit-user', ['only' => ['edit','update']]);
$this->middleware('permission:delete-user', ['only' => ['destroy']]);
}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('users.index', [
'users' => User::latest('id')->paginate(3)
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('users.create', [
'roles' => Role::pluck('name')->all()
]);
}
/**
* Store a newly created resource in storage.
*/
public function store(StoreUserRequest $request): RedirectResponse
{
$input = $request->all();
$input['password'] = Hash::make($request->password);
$user = User::create($input);
$user->assignRole($request->roles);
return redirect()->route('users.index')
->withSuccess('New user is added successfully.');
}
/**
* Display the specified resource.
*/
public function show(User $user): View
{
return view('users.show', [
'user' => $user
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(User $user): View
{
// Check Only Super Admin can update his own Profile
if ($user->hasRole('Super Admin')){
if($user->id != auth()->user()->id){
abort(403, 'USER DOES NOT HAVE THE RIGHT PERMISSIONS');
}
}
return view('users.edit', [
'user' => $user,
'roles' => Role::pluck('name')->all(),
'userRoles' => $user->roles->pluck('name')->all()
]);
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateUserRequest $request, User $user): RedirectResponse
{
$input = $request->all();
if(!empty($request->password)){
$input['password'] = Hash::make($request->password);
}else{
$input = $request->except('password');
}
$user->update($input);
$user->syncRoles($request->roles);
return redirect()->back()
->withSuccess('User is updated successfully.');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(User $user): RedirectResponse
{
// About if user is Super Admin or User ID belongs to Auth User
if ($user->hasRole('Super Admin') || $user->id == auth()->user()->id)
{
abort(403, 'USER DOES NOT HAVE THE RIGHT PERMISSIONS');
}
$user->syncRoles([]);
$user->delete();
return redirect()->route('users.index')
->withSuccess('User is deleted successfully.');
}
}
ProductController.php
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use App\Http\Requests\StoreProductRequest;
use App\Http\Requests\UpdateProductRequest;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
class ProductController extends Controller
{
/**
* Instantiate a new ProductController instance.
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('permission:create-product|edit-product|delete-product', ['only' => ['index','show']]);
$this->middleware('permission:create-product', ['only' => ['create','store']]);
$this->middleware('permission:edit-product', ['only' => ['edit','update']]);
$this->middleware('permission:delete-product', ['only' => ['destroy']]);
}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('products.index', [
'products' => Product::latest()->paginate(3)
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('products.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(StoreProductRequest $request): RedirectResponse
{
Product::create($request->all());
return redirect()->route('products.index')
->withSuccess('New product is added successfully.');
}
/**
* Display the specified resource.
*/
public function show(Product $product): View
{
return view('products.show', [
'product' => $product
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Product $product): View
{
return view('products.edit', [
'product' => $product
]);
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateProductRequest $request, Product $product): RedirectResponse
{
$product->update($request->all());
return redirect()->back()
->withSuccess('Product is updated successfully.');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Product $product): RedirectResponse
{
$product->delete();
return redirect()->route('products.index')
->withSuccess('Product is deleted successfully.');
}
}
16. Make Role and User Form Requests
Run the below commands to create role and user form requests, you can run all commands together as well.
php artisan make:request StoreRoleRequest
php artisan make:request UpdateRoleRequest
php artisan make:request StoreUserRequest
php artisan make:request UpdateUserRequest
17. Update Role, User and Product Store and Update Form Requests
Now update role, user and product store and update form requests. Just go to the app\Http\Requests and update the below files.
StoreRoleRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreRoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250|unique:roles,name',
'permissions' => 'required',
];
}
}
UpdateRoleRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateRoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250|unique:roles,name,'.$this->role->id,
'permissions' => 'required',
];
}
}
StoreUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250',
'email' => 'required|string|email:rfc,dns|max:250|unique:users,email',
'password' => 'required|string|min:8|confirmed',
'roles' => 'required'
];
}
}
UpdateUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250',
'email' => 'required|string|email:rfc,dns|max:250|unique:users,email,'.$this->user->id,
'password' => 'nullable|string|min:8|confirmed',
'roles' => 'required'
];
}
}
StoreProductRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250',
'description' => 'required|string'
];
}
}
UpdateProductRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:250',
'description' => 'required|string'
];
}
}
18. Create Role, User and Product Resource Blade View Files
Now, we need to create role, user and product resource blade view files in the relevant directories in the resources\views directory.
We need to create users, roles and products directories in resources\views.
We can create them either like always we used to do manually but with Laravel 10, now you can create them using PHP artisan command so just run the below commands and all 12 blade view files will be created in the relevant directory.
php artisan make:view users.index
php artisan make:view users.create
php artisan make:view users.edit
php artisan make:view users.show
php artisan make:view roles.index
php artisan make:view roles.create
php artisan make:view roles.edit
php artisan make:view roles.show
php artisan make:view products.index
php artisan make:view products.create
php artisan make:view products.edit
php artisan make:view products.show
Now, we need to update each blade file with the following code.
First we will update role view files, just navigate to the resources\views\roles\ directory and update the following files.
- index.blade.php
- create.blade.php
- edit.blade.php
- show.blade.php
index.blade.php
@extends('layouts.app')
@section('content')
<div class="card">
<div class="card-header">Manage Roles</div>
<div class="card-body">
@can('create-role')
<a href="{{ route('roles.create') }}" class="btn btn-success btn-sm my-2"><i class="bi bi-plus-circle"></i> Add New Role</a>
@endcan
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">S#</th>
<th scope="col">Name</th>
<th scope="col" style="width: 250px;">Action</th>
</tr>
</thead>
<tbody>
@forelse ($roles as $role)
<tr>
<th scope="row">{{ $loop->iteration }}</th>
<td>{{ $role->name }}</td>
<td>
<form action="{{ route('roles.destroy', $role->id) }}" method="post">
@csrf
@method('DELETE')
<a href="{{ route('roles.show', $role->id) }}" class="btn btn-warning btn-sm"><i class="bi bi-eye"></i> Show</a>
@if ($role->name!='Super Admin')
@can('edit-role')
<a href="{{ route('roles.edit', $role->id) }}" class="btn btn-primary btn-sm"><i class="bi bi-pencil-square"></i> Edit</a>
@endcan
@can('delete-role')
@if ($role->name!=Auth::user()->hasRole($role->name))
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Do you want to delete this role?');"><i class="bi bi-trash"></i> Delete</button>
@endif
@endcan
@endif
</form>
</td>
</tr>
@empty
<td colspan="3">
<span class="text-danger">
<strong>No Role Found!</strong>
</span>
</td>
@endforelse
</tbody>
</table>
{{ $roles->links() }}
</div>
</div>
@endsection
create.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Add New Role
</div>
<div class="float-end">
<a href="{{ route('roles.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('roles.store') }}" method="post">
@csrf
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="permissions" class="col-md-4 col-form-label text-md-end text-start">Permissions</label>
<div class="col-md-6">
<select class="form-select @error('permissions') is-invalid @enderror" multiple aria-label="Permissions" id="permissions" name="permissions[]" style="height: 210px;">
@forelse ($permissions as $permission)
<option value="{{ $permission->id }}" {{ in_array($permission->id, old('permissions') ?? []) ? 'selected' : '' }}>
{{ $permission->name }}
</option>
@empty
@endforelse
</select>
@if ($errors->has('permissions'))
<span class="text-danger">{{ $errors->first('permissions') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Add Role">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
edit.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Edit Role
</div>
<div class="float-end">
<a href="{{ route('roles.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('roles.update', $role->id) }}" method="post">
@csrf
@method("PUT")
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ $role->name }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="permissions" class="col-md-4 col-form-label text-md-end text-start">Permissions</label>
<div class="col-md-6">
<select class="form-select @error('permissions') is-invalid @enderror" multiple aria-label="Permissions" id="permissions" name="permissions[]" style="height: 210px;">
@forelse ($permissions as $permission)
<option value="{{ $permission->id }}" {{ in_array($permission->id, $rolePermissions ?? []) ? 'selected' : '' }}>
{{ $permission->name }}
</option>
@empty
@endforelse
</select>
@if ($errors->has('permissions'))
<span class="text-danger">{{ $errors->first('permissions') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Update Role">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
show.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Role Information
</div>
<div class="float-end">
<a href="{{ route('roles.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start"><strong>Name:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
{{ $role->name }}
</div>
</div>
<div class="mb-3 row">
<label for="roles" class="col-md-4 col-form-label text-md-end text-start"><strong>Permissions:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
@if ($role->name=='Super Admin')
<span class="badge bg-primary">All</span>
@else
@forelse ($rolePermissions as $permission)
<span class="badge bg-primary">{{ $permission->name }}</span>
@empty
@endforelse
@endif
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
After that we will update user view files, just navigate to the resources\views\users\ directory and update the following files.
- index.blade.php
- create.blade.php
- edit.blade.php
- show.blade.php
index.blade.php
@extends('layouts.app')
@section('content')
<div class="card">
<div class="card-header">Manage Users</div>
<div class="card-body">
@can('create-user')
<a href="{{ route('users.create') }}" class="btn btn-success btn-sm my-2"><i class="bi bi-plus-circle"></i> Add New User</a>
@endcan
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">S#</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Roles</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
@forelse ($users as $user)
<tr>
<th scope="row">{{ $loop->iteration }}</th>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>
@forelse ($user->getRoleNames() as $role)
<span class="badge bg-primary">{{ $role }}</span>
@empty
@endforelse
</td>
<td>
<form action="{{ route('users.destroy', $user->id) }}" method="post">
@csrf
@method('DELETE')
<a href="{{ route('users.show', $user->id) }}" class="btn btn-warning btn-sm"><i class="bi bi-eye"></i> Show</a>
@if (in_array('Super Admin', $user->getRoleNames()->toArray() ?? []) )
@if (Auth::user()->hasRole('Super Admin'))
<a href="{{ route('users.edit', $user->id) }}" class="btn btn-primary btn-sm"><i class="bi bi-pencil-square"></i> Edit</a>
@endif
@else
@can('edit-user')
<a href="{{ route('users.edit', $user->id) }}" class="btn btn-primary btn-sm"><i class="bi bi-pencil-square"></i> Edit</a>
@endcan
@can('delete-user')
@if (Auth::user()->id!=$user->id)
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Do you want to delete this user?');"><i class="bi bi-trash"></i> Delete</button>
@endif
@endcan
@endif
</form>
</td>
</tr>
@empty
<td colspan="5">
<span class="text-danger">
<strong>No User Found!</strong>
</span>
</td>
@endforelse
</tbody>
</table>
{{ $users->links() }}
</div>
</div>
@endsection
create.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Add New User
</div>
<div class="float-end">
<a href="{{ route('users.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('users.store') }}" method="post">
@csrf
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="email" class="col-md-4 col-form-label text-md-end text-start">Email Address</label>
<div class="col-md-6">
<input type="email" class="form-control @error('email') is-invalid @enderror" id="email" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="text-danger">{{ $errors->first('email') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="password" class="col-md-4 col-form-label text-md-end text-start">Password</label>
<div class="col-md-6">
<input type="password" class="form-control @error('password') is-invalid @enderror" id="password" name="password">
@if ($errors->has('password'))
<span class="text-danger">{{ $errors->first('password') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="password_confirmation" class="col-md-4 col-form-label text-md-end text-start">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" id="password_confirmation" name="password_confirmation">
</div>
</div>
<div class="mb-3 row">
<label for="roles" class="col-md-4 col-form-label text-md-end text-start">Roles</label>
<div class="col-md-6">
<select class="form-select @error('roles') is-invalid @enderror" multiple aria-label="Roles" id="roles" name="roles[]">
@forelse ($roles as $role)
@if ($role!='Super Admin')
<option value="{{ $role }}" {{ in_array($role, old('roles') ?? []) ? 'selected' : '' }}>
{{ $role }}
</option>
@else
@if (Auth::user()->hasRole('Super Admin'))
<option value="{{ $role }}" {{ in_array($role, old('roles') ?? []) ? 'selected' : '' }}>
{{ $role }}
</option>
@endif
@endif
@empty
@endforelse
</select>
@if ($errors->has('roles'))
<span class="text-danger">{{ $errors->first('roles') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Add User">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
edit.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Edit User
</div>
<div class="float-end">
<a href="{{ route('users.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('users.update', $user->id) }}" method="post">
@csrf
@method("PUT")
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ $user->name }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="email" class="col-md-4 col-form-label text-md-end text-start">Email Address</label>
<div class="col-md-6">
<input type="email" class="form-control @error('email') is-invalid @enderror" id="email" name="email" value="{{ $user->email }}">
@if ($errors->has('email'))
<span class="text-danger">{{ $errors->first('email') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="password" class="col-md-4 col-form-label text-md-end text-start">Password</label>
<div class="col-md-6">
<input type="password" class="form-control @error('password') is-invalid @enderror" id="password" name="password">
@if ($errors->has('password'))
<span class="text-danger">{{ $errors->first('password') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="password_confirmation" class="col-md-4 col-form-label text-md-end text-start">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" id="password_confirmation" name="password_confirmation">
</div>
</div>
<div class="mb-3 row">
<label for="roles" class="col-md-4 col-form-label text-md-end text-start">Roles</label>
<div class="col-md-6">
<select class="form-select @error('roles') is-invalid @enderror" multiple aria-label="Roles" id="roles" name="roles[]">
@forelse ($roles as $role)
@if ($role!='Super Admin')
<option value="{{ $role }}" {{ in_array($role, $userRoles ?? []) ? 'selected' : '' }}>
{{ $role }}
</option>
@else
@if (Auth::user()->hasRole('Super Admin'))
<option value="{{ $role }}" {{ in_array($role, $userRoles ?? []) ? 'selected' : '' }}>
{{ $role }}
</option>
@endif
@endif
@empty
@endforelse
</select>
@if ($errors->has('roles'))
<span class="text-danger">{{ $errors->first('roles') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Update User">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
show.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
User Information
</div>
<div class="float-end">
<a href="{{ route('users.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start"><strong>Name:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
{{ $user->name }}
</div>
</div>
<div class="mb-3 row">
<label for="email" class="col-md-4 col-form-label text-md-end text-start"><strong>Email Address:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
{{ $user->email }}
</div>
</div>
<div class="mb-3 row">
<label for="roles" class="col-md-4 col-form-label text-md-end text-start"><strong>Roles:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
@forelse ($user->getRoleNames() as $role)
<span class="badge bg-primary">{{ $role }}</span>
@empty
@endforelse
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
Finally we will update product view files, just navigate to the resources\views\products\ directory and update the following files.
- index.blade.php
- create.blade.php
- edit.blade.php
- show.blade.php
index.blade.php
@extends('layouts.app')
@section('content')
<div class="card">
<div class="card-header">Product List</div>
<div class="card-body">
@can('create-product')
<a href="{{ route('products.create') }}" class="btn btn-success btn-sm my-2"><i class="bi bi-plus-circle"></i> Add New Product</a>
@endcan
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">S#</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
@forelse ($products as $product)
<tr>
<th scope="row">{{ $loop->iteration }}</th>
<td>{{ $product->name }}</td>
<td>{{ $product->description }}</td>
<td>
<form action="{{ route('products.destroy', $product->id) }}" method="post">
@csrf
@method('DELETE')
<a href="{{ route('products.show', $product->id) }}" class="btn btn-warning btn-sm"><i class="bi bi-eye"></i> Show</a>
@can('edit-product')
<a href="{{ route('products.edit', $product->id) }}" class="btn btn-primary btn-sm"><i class="bi bi-pencil-square"></i> Edit</a>
@endcan
@can('delete-product')
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Do you want to delete this product?');"><i class="bi bi-trash"></i> Delete</button>
@endcan
</form>
</td>
</tr>
@empty
<td colspan="4">
<span class="text-danger">
<strong>No Product Found!</strong>
</span>
</td>
@endforelse
</tbody>
</table>
{{ $products->links() }}
</div>
</div>
@endsection
create.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Add New Product
</div>
<div class="float-end">
<a href="{{ route('products.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('products.store') }}" method="post">
@csrf
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="description" class="col-md-4 col-form-label text-md-end text-start">Description</label>
<div class="col-md-6">
<textarea class="form-control @error('description') is-invalid @enderror" id="description" name="description">{{ old('description') }}</textarea>
@if ($errors->has('description'))
<span class="text-danger">{{ $errors->first('description') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Add Product">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
edit.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Edit Product
</div>
<div class="float-end">
<a href="{{ route('products.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<form action="{{ route('products.update', $product->id) }}" method="post">
@csrf
@method("PUT")
<div class="mb-3 row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start">Name</label>
<div class="col-md-6">
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ $product->name }}">
@if ($errors->has('name'))
<span class="text-danger">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<label for="description" class="col-md-4 col-form-label text-md-end text-start">Description</label>
<div class="col-md-6">
<textarea class="form-control @error('description') is-invalid @enderror" id="description" name="description">{{ $product->description }}</textarea>
@if ($errors->has('description'))
<span class="text-danger">{{ $errors->first('description') }}</span>
@endif
</div>
</div>
<div class="mb-3 row">
<input type="submit" class="col-md-3 offset-md-5 btn btn-primary" value="Update">
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
show.blade.php
@extends('layouts.app')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="float-start">
Product Information
</div>
<div class="float-end">
<a href="{{ route('products.index') }}" class="btn btn-primary btn-sm">← Back</a>
</div>
</div>
<div class="card-body">
<div class="row">
<label for="name" class="col-md-4 col-form-label text-md-end text-start"><strong>Name:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
{{ $product->name }}
</div>
</div>
<div class="row">
<label for="description" class="col-md-4 col-form-label text-md-end text-start"><strong>Description:</strong></label>
<div class="col-md-6" style="line-height: 35px;">
{{ $product->description }}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
19. Update Application Layout and Home Blade View Files
In this step, we will need to update application layout and home blade view files. Just go to the resources\views\layouts and update following code in app.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">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Simple Laravel 10 User Roles and Permissions - AllPHPTricks.com</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<!-- Scripts -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
AllPHPTricks.com
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
@canany(['create-role', 'edit-role', 'delete-role'])
<li><a class="nav-link" href="{{ route('roles.index') }}">Manage Roles</a></li>
@endcanany
@canany(['create-user', 'edit-user', 'delete-user'])
<li><a class="nav-link" href="{{ route('users.index') }}">Manage Users</a></li>
@endcanany
@canany(['create-product', 'edit-product', 'delete-product'])
<li><a class="nav-link" href="{{ route('products.index') }}">Manage Products</a></li>
@endcanany
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-md-12">
@if ($message = Session::get('success'))
<div class="alert alert-success text-center" role="alert">
{{ $message }}
</div>
@endif
<h3 class="text-center mt-3 mb-3">Simple Laravel 10 User Roles and Permissions - <a href="https://www.allphptricks.com/">AllPHPTricks.com</a></h3>
@yield('content')
<div class="row justify-content-center text-center mt-3">
<div class="col-md-12">
<p>Back to Tutorial:
<a href="https://www.allphptricks.com/simple-laravel-10-user-roles-and-permissions/"><strong>Tutorial Link</strong></a>
</p>
<p>
For More Web Development Tutorials Visit: <a href="https://www.allphptricks.com/"><strong>AllPHPTricks.com</strong></a>
</p>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</body>
</html>
Now go to the resources\views and update code in home.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">{{ __('Dashboard') }}</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
{{ __('You are logged in!') }}
<p>This is your application dashboard.</p>
@canany(['create-role', 'edit-role', 'delete-role'])
<a class="btn btn-primary" href="{{ route('roles.index') }}">
<i class="bi bi-person-fill-gear"></i> Manage Roles</a>
@endcanany
@canany(['create-user', 'edit-user', 'delete-user'])
<a class="btn btn-success" href="{{ route('users.index') }}">
<i class="bi bi-people"></i> Manage Users</a>
@endcanany
@canany(['create-product', 'edit-product', 'delete-product'])
<a class="btn btn-warning" href="{{ route('products.index') }}">
<i class="bi bi-bag"></i> Manage Products</a>
@endcanany
<p> </p>
</div>
</div>
</div>
</div>
</div>
@endsection
20. Run Laravel Development Server
We have finally completed our Laravel 10 User Roles and Permissions application, so now it is the time to run and test the application. Run the Laravel development server by running the below command.
php artisan serve
Once the server started, open the application on the browser by visiting the link mentioned below.
http://127.0.0.1:8000/login
And enter the below credentials to test the application with different roles and permissions.
//Super Admin Credentials
Email: [email protected]
Password: javed1234
//Admin Credentials
Email: [email protected]
Password: ahsan1234
//Product Manager Credentials
Email: [email protected]
Password: muqeet1234
Conclusion
By now we hope that you have learnt how to easily create a simple Laravel user roles and permissions application by following the above simple and step by step guide.
If you found this tutorial helpful, share it with your friends and developers group.
I spent several hours to create this tutorial, if you want to say thanks so like my page on Facebook, Twitter and share it.
Facebook Official Page: All PHP Tricks
Twitter Official Page: All PHP Tricks
Merci beaucoup ça m’a été très utile
Glad to know that you found it useful Mariam. Thanks for the appreciation.
Gracias por esta informacion, soy un viejo programador de la epoca de los 80 y 90 y estoy queriendo ponerme a dia y este pequeño manual me ha sido de mucha utilidad.
Muchas gracias por el aporte.
Si tienes informacion que me pueda ser util para aprender laravel , enviame a mi mail. saludos desde Ecuador.
Glad to know that you found it useful and helpful.
Hi, great tutorial.
Question about having Permissions as part of the GUI, rather than just in DB.
What are your thoughts, is it a good idea to add UI for Permissions?
Thanks.
It is good practice to keep such information in database instead of hardcoding them in files.
Hello and thanks for this very nice tutorial. It really helped me. I was wondering that if I create new methods on the products controller, are they automatically protected and will only be accessible if I add the permissions for them? I tried this but the new methods were not protected this way. Can you help me?
Thankyou so much for clean concept of roles and permissions, was frustrted before, but now back in energy and positivity due to your knwoldege. May Allah bless you and your family. 🙂
Dear Adnan,
Thanks for your prayer and appreciation. Glad to know that you found this tutorial helpful.
JazakAllah
I finished the tutorial and I can login and see home. But when I try to open roles, users or products I get this error:
Target class [permission] does not exist.
What am I doing wrong?
Dear Ronaldo,
Have you created and migrated Roles and Permission seeders to add data into your database?
Hello! You have a great article compared to others.
But there is one problem, after installing ckeditor for textarea, traction does not work and is output as plain text.
Can you tell me how to fix this problem?
Thanks!
Dear Andry,
Thanks for the appreciation, and I am glad to know that you found it helpful.
I didn’t tested it with ckeditor, you should make sure that ckeditor is loaded without any error, check your console.log in browser to find the issue.
ckeditor usually does not work if its library does not loaded or loaded twice.
Happy Coding. 🙂
Sir, Thank you so much for tutorial, it’s works!! you saved me 🙂
You are most welcome, happy to know that you found this tutorial helpful.
I experienced an error like this, what is wrong?
Too few arguments to function Spatie\Permission\Middleware\RoleMiddleware::handle()
Dear Roly, can you share that on which file you are getting this error?
make sure that you are using the same version of Laravel and Spatie like this tutorial.
If you are using previous version then you should look into the documentation of Spatie to fix your issue.
I created an Admin model & controller. Tried to implement this with the Admin model. But it’s not working.
Then I change the code for the User Model & Controller. Then it works.
Would you please tell me why this happened?
Dear Shahriar,
As you can see that we are using the Laravel package that is using the default user model, if you want to change that table then you will need to implement it on all pages where User model is used.
You can read more about it in that package guide which will help you to change the user table with your own.
I have access the dashboard of particular users that was registered. but in dashboard only displaying “You are logged in!
This is your application dashboard.”
Noting show else expect above statement.
Dear Ghulam,
As you can see in home.blade.php view file, we show this message to logged in user, now you can display any message to them or anything that you like to show to logged in users.
Hi,
CSS is not working. What could be the problem?
Thank you!!
It’s very helpful.
I was searching for a tutorial that can help me to understand Laravel roles and permissions but I was thinking that it is very difficult concept but your tutorial make it very for me to understand such complex concept. Thanks for sharing such a useful tutorial which covers all required information and explain very clearly. Thanks again.
Dear Melkie,
Thanks for your kind comment, we are glad that you found our tutorial helpful.
Please help me
error:
SQLSTATE[42S02]: Base table or view not found: 1146 La table ‘dbroles.roles’ n’existe pas
select `roles`.*, `model_has_roles`.`model_id` as `pivot_model_id`, `model_has_roles`.`role_id` as `pivot_role_id`, `model_has_roles`.`model_type` as `pivot_model_type` from `roles` inner join `model_has_roles` on `roles`.`id` = `model_has_roles`.`role_id` where `model_has_roles`.`model_id` in (1) and `model_has_roles`.`model_type` = App\Models\User
Dear Ben,
Kindly make sure that all tables of spatie has been migrated to your database.
Thank you so much for this wonderful tutorial. I have tried it in my local server. However, in SuperAdminSeeder.php file,
'password' => Hash::make('javed1234')
was not working, I had put a back slash before ‘Hash’, and now it is fine.
Another thing in UserController.php file. It seems the method show(string $user) needs little attention? It displays error ‘Attempt to read property “name” on string’ in a blade file. Though I have made some changes and it is working for me now :).
Again, thanks a lot for this impressive effort, keep up the good work 🙂
Dear Mohammad Rezaul Islam,
Thanks for your kind contribution, I do test before share code but yeah it is true, error may occur because if version of anything changes then it may break. But I am glad that you find it useful.
The corrected path on protected $middlewareAliasesis = [
‘role’ => \Spatie\Permission\Middleware\RoleMiddleware::class,
‘permission’ => \Spatie\Permission\Middleware\PermissionMiddleware::class,
‘role_or_permission’ => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
]
– The difference with the one posted on this blog is ‘\Middlewares\’ so I changed the directory to ‘\Middleware\’.
– Applicable in laravel 10 and “spatie/laravel-permission”: “^6.0”,
Dear miGo,
Thanks for your input and indicating the issue. Previously, this tutorial was using the Laravel Saptie permission package version 5, therefore we were using S in the middleware aliases. However, we have updated this tutorial to version 6 of Saptie Laravel permission.
We appreciate your input and time.
Thank you so much for this. Excellent tutorial and was exactly what I was looking for.
Thanks for the appreciation William, I am glad that you found my tutorial helping. I was also struggling to find something that can provide me complete details about Laravel user roles and permissions. When I failed to find one then I thought that I should create one to help others.