Hello Artisan,
In this brand new spatie laravel permission tutorial, I am going to show you the uses of spatie laravel roles and permissions tutorial. I will start from scratch so that you can understand the source code easily. I will explain in this example, simply step by step laravel 8 spatie/laravel-permission and also step by step explain laravel 8 acl tutorial.
You know that the Spatie role permission composer package provides a way to create ACL in laravel 8. It also provide how to assign a role to a user very easily, How to assign permission to a user and how to assign permission assign to roles This package allows you to manage user permissions and roles in a database.
Before I have created two tutorials about laravel roles and permission. One was laravel roles and permission without packages and another was Laravel role role and permission tutorial step by step using laratrus
permission package.
But in this example, I will use spatie roles and permissions package to control user access in Laravel application. Before started this tutorial, please read below article, which helps you to understand the concept of how spatie works.
Recommended : Laravel 8 User Roles and Permissions Tutorial using Laratrust Package
Recommended : User Roles and Permissions Tutorial in Laravel Without Packages
Let's start our spatie roles and permission tutorial.
Step 1: Download Laravel
I'm going from scratch so, If you haven't installed laravel in your system then you can run bellow command and get fresh Laravel project.
composer create-project --prefer-dist laravel/laravel blog
Step 2: Install Spatie Packages
Now we need to install Spatie package for ACL, that way we can use it's a method. Also, we will install a form collection package. So Open your terminal and run below command.
composer require spatie/laravel-permission
//and then
composer require laravelcollective/html
Now open config/app.php
file and add service provider and alias.
config/app.php
'providers' => [
....
Spatie\Permission\PermissionServiceProvider::class,
],
We can also custom changes on the Spatie package, so if you also want to changes then you can fire the below command and get the config file in config/permission.php and migration files.
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
Now run migrate command.
php artisan migrate
Recommended : Laravel Passport Scope Tutorial | API Permissions Using Passport Scope
Step 3: Create Product Model and Migration
In this step we need to create three migration for products table as using bellow command:
php artisan make:model Product -m
Update product migration like
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('detail');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('products');
}
}
Now run the migration:
php artisan migrate
Step 4: Update Models
In this step, we have to create a model for the User and Product table, so if you get a fresh project then you have a User Model have so just replaced the code and others you should create.
app/Models/User.php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasRoles;
}
Update product model like
app/Models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'name', 'detail'
];
}
Step 5: Register Middleware
Spatie package provides its in-built middleware that way we can use it display as bellow. So, we have to add middleware in the Kernel.php
file this way :
app/Http/Kernel.php
....
protected $routeMiddleware = [
....
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
]
....
Step 6: Create Auth
In this step, we need to set up laravel default authentication.
composer require laravel/ui
php artisan ui bootstrap --auth
npm install
npm run dev
Step 7: Add Routes
We require to add a number of routes for the user's module, products module, and roles module. In this route i also use middleware with permission for roles and products route, so add route this way:
routes/web.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;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::group(['middleware' => ['auth']], function() {
Route::resource('roles', RoleController::class);
Route::resource('users', UserController::class);
Route::resource('products', ProductController::class);
});
Step 8: Create Controllers
In this step we have to add three controllers for user's module, products module and roles module so you can create three controllers like as bellow:
app/Http/Controllers/UserController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\User;
use Spatie\Permission\Models\Role;
use DB;
use Hash;
use Illuminate\Support\Arr;
class UserController extends Controller
{
public function index(Request $request)
{
$data = User::orderBy('id','DESC')->paginate(5);
return view('users.index',compact('data'));
}
public function create()
{
$roles = Role::pluck('name','name')->all();
return view('users.create',compact('roles'));
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email|unique:users,email',
'password' => 'required|same:confirm-password',
'roles' => 'required'
]);
$input = $request->all();
$input['password'] = Hash::make($input['password']);
$user = User::create($input);
$user->assignRole($request->input('roles'));
return redirect()->route('users.index')
->with('success','User created successfully');
}
public function show($id)
{
$user = User::find($id);
return view('users.show',compact('user'));
}
public function edit($id)
{
$user = User::find($id);
$roles = Role::pluck('name','name')->all();
$userRole = $user->roles->pluck('name','name')->all();
return view('users.edit',compact('user','roles','userRole'));
}
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email|unique:users,email,'.$id,
'password' => 'same:confirm-password',
'roles' => 'required'
]);
$input = $request->all();
if(!empty($input['password'])){
$input['password'] = Hash::make($input['password']);
}else{
$input = Arr::except($input,array('password'));
}
$user = User::find($id);
$user->update($input);
DB::table('model_has_roles')->where('model_id',$id)->delete();
$user->assignRole($request->input('roles'));
return redirect()->route('users.index')
->with('success','User updated successfully');
}
public function destroy($id)
{
User::find($id)->delete();
return redirect()->route('users.index')
->with('success','User deleted successfully');
}
}
Update the productController like below
app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
function __construct()
{
$this->middleware('permission:product-list|product-create|product-edit|product-delete', ['only' => ['index','show']]);
$this->middleware('permission:product-create', ['only' => ['create','store']]);
$this->middleware('permission:product-edit', ['only' => ['edit','update']]);
$this->middleware('permission:product-delete', ['only' => ['destroy']]);
}
public function index()
{
$products = Product::latest()->paginate(5);
return view('products.index',compact('products'));
}
public function create()
{
return view('products.create');
}
public function store(Request $request)
{
request()->validate([
'name' => 'required',
'detail' => 'required',
]);
Product::create($request->all());
return redirect()->route('products.index')
->with('success','Product created successfully.');
}
public function show(Product $product)
{
return view('products.show',compact('product'));
}
public function edit(Product $product)
{
return view('products.edit',compact('product'));
}
public function update(Request $request, Product $product)
{
request()->validate([
'name' => 'required',
'detail' => 'required',
]);
$product->update($request->all());
return redirect()->route('products.index')
->with('success','Product updated successfully');
}
public function destroy(Product $product)
{
$product->delete();
return redirect()->route('products.index')
->with('success','Product deleted successfully');
}
}
And update role controller as well like below
app/Http/Controllers/RoleController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use DB;
class RoleController extends Controller
{
function __construct()
{
$this->middleware('permission:role-list|role-create|role-edit|role-delete', ['only' => ['index','store']]);
$this->middleware('permission:role-create', ['only' => ['create','store']]);
$this->middleware('permission:role-edit', ['only' => ['edit','update']]);
$this->middleware('permission:role-delete', ['only' => ['destroy']]);
}
public function index(Request $request)
{
$roles = Role::orderBy('id','DESC')->paginate(5);
return view('roles.index',compact('roles'));
}
public function create()
{
$permission = Permission::get();
return view('roles.create',compact('permission'));
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|unique:roles,name',
'permission' => 'required',
]);
$role = Role::create(['name' => $request->input('name')]);
$role->syncPermissions($request->input('permission'));
return redirect()->route('roles.index')
->with('success','Role created successfully');
}
public function show($id)
{
$role = Role::find($id);
$rolePermissions = Permission::join("role_has_permissions","role_has_permissions.permission_id","=","permissions.id")
->where("role_has_permissions.role_id",$id)
->get();
return view('roles.show',compact('role','rolePermissions'));
}
public function edit($id)
{
$role = Role::find($id);
$permission = Permission::get();
$rolePermissions = DB::table("role_has_permissions")->where("role_has_permissions.role_id",$id)
->pluck('role_has_permissions.permission_id','role_has_permissions.permission_id')
->all();
return view('roles.edit',compact('role','permission','rolePermissions'));
}
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required',
'permission' => 'required',
]);
$role = Role::find($id);
$role->name = $request->input('name');
$role->save();
$role->syncPermissions($request->input('permission'));
return redirect()->route('roles.index')
->with('success','Role updated successfully');
}
public function destroy($id)
{
DB::table("roles")->where('id',$id)->delete();
return redirect()->route('roles.index')
->with('success','Role deleted successfully');
}
}
Step 9: Create Blade Files
In this step, we need to create some frontend module to check user roles and permissions in laravel with spatie permission packages. So let's create one after another:
resources/views/layouts/app.blade.php
resources/views/users/index.blade.php
I have used collective form, but you can ignore it with normal HTML form.
resources/views/users/create.blade.php
resources/views/users/edit.blade.php
resources/views/users/show.blade.php
resources/views/roles/index.blade.php
resources/views/roles/create.blade.php
resources/views/roles/edit.blade.php
resources/views/roles/show.blade.php
resources/views/products/index.blade.php
resources/views/products/create.blade.php
resources/views/products/edit.blade.php
resources/views/products/show.blade.php
Step 10: Create Seeder
We need some dummy data to check user roles and permissions in laravel. We will create some fake data using laravel database seeder. let's create it:
php artisan make:seeder PermissionTableSeeder
//and then
php artisan make:seeder CreateAdminUserSeeder
And update the PermissionTableSeeder file this way:
database/seeds/PermissionTableSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
class PermissionTableSeeder extends Seeder
{
public function run()
{
$permissions = [
'role-list',
'role-create',
'role-edit',
'role-delete',
'product-list',
'product-create',
'product-edit',
'product-delete'
];
foreach ($permissions as $permission) {
Permission::create(['name' => $permission]);
}
}
}
And now update the admin seed like below
database/seeds/CreateAdminUserSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
class CreateAdminUserSeeder extends Seeder
{
public function run()
{
$user = User::create([
'name' => 'Hardik Savani',
'email' => 'admin@gmail.com',
'password' => bcrypt('123456')
]);
$role = Role::create(['name' => 'Admin']);
$permissions = Permission::pluck('id','id')->all();
$role->syncPermissions($permissions);
$user->assignRole([$role->id]);
}
}
Now run db:seed
command to generate some fake data.
php artisan db:seed --class=PermissionTableSeeder
php artisan db:seed --class=CreateAdminUserSeeder
Now we are ready to run full example of ACL. so let's run our example so run bellow command to start the server:
php artisan serve
And visit the below url to check:
Recommended: Vue Laravel CRUD Example With Vue Router & Sweet Alert
Now all are set to go. Hope it can help you.
#laravel #laravel-8x #role #permission #authorization #acl