Courses

Filament 3 From Scratch: Practical Course

Shield Plugin for Roles and Permissions

Summary of this lesson:
- Implementing Shield package
- Managing roles and permissions
- Assigning roles to users
- Configuring access control

Until now, we checked if the user can do something by checking if users.is_admin or users.is_accountant is true.

This can be done better by using roles and permissions. And Filament has an excellent plugin for that called Shield which under the hood uses spatie/laravel-permission package.

This lesson will use the Shield package to add roles and permissions functionality.

roles


Composer Install Package

First, let's install the package via composer.

composer require bezhansalleh/filament-shield "^3.0@beta"

Then we need to add Spatie\Permission\Traits\HasRoles trait to the User Model.

app/Models/User.php:

use Spatie\Permission\Traits\HasRoles;
 
class User extends Authenticatable implements FilamentUser
{
use HasApiTokens, HasFactory, Notifiable;
use HasRoles;
 
// ...
}

Next, we need to register this package in the panel.

app/Providers/Filament/AdminPanelProvider.php:

class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
\BezhanSalleh\FilamentShield\FilamentShieldPlugin::make()
]);
}
}

If you have multiple panels, you may choose to add it only for admin users. This way, only users with access to that panel will have access to the Roles resource.

And now, we can run the installation of the package.

php artisan shield:install

After following the prompts, the package will publish the config file and permissions migration and will run it. It will also create Policies for all Filament Resources, Pages, and Widgets.

In the end, it will show all the users and will ask to provide an ID of the user to set for a super_admin role.

prompt select admin user

After logging into the admin panel, we can see a new navigation item:

shield navigation


Add New Role

By default, Shield created two roles: super_admin and filament_user. Our goal is to replace the is_accountant DB field, so for that, we will make an Accountant role.

Go to Roles and press New Role. The name will be accountant. As for permissions, this role only needs access to the Order, so check the Order from the resources tab.

accountant role creation

Now we need to allow admin only to the /admin panel and accountant only to the /accountant panel. This access is done in the User Model canAccessPanel method.

app/Models/User.php:

class User extends Authenticatable implements FilamentUser
{
// ...
 
public function canAccessPanel(Panel $panel): bool
{
return true;
if ($panel->getId() === 'admin') {
return $this->hasRole('super_admin');
}
 
if ($panel->getId() === 'accountant') {
return $this->hasRole('accountant');
}
 
return false;
}
}

And that's it. Everything else works as expected, and now we have a powerful roles system with a friendly GUI.


Assign Role to a User

Shield plugin has a roles/permission manager, but doesn't have the feature to assign a role to a user. But luckily, we have a UserResouce, and we can achieve the goal quickly using the Select form field.

app/Filament/Resources/UserResource.php:

class UserResource extends Resource
{
protected static ?string $model = User::class;
 
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name'),
Forms\Components\TextInput::make('email')->email(),
Forms\Components\Select::make('roles')
->preload()
->multiple()
->relationship('roles', 'name')
->columnSpan('full'),
]);
}
 
// ...
}

That's how easy it was.

assign role to a user

If you want to see roles in the table, it's just one line of the code.

app/Filament/Resources/UserResource.php:

class UserResource extends Resource
{
// ...
 
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('email'),
Tables\Columns\TextColumn::make('roles.name'),
Tables\Columns\TextColumn::make('created_at')
->dateTime(),
])
// ...
}
 
// ...
}

users table with roles


Course Conclusion (For Now)

So, that's all I've chosen to talk about in this course about core features of Filament 3.

The repository for this course is available on GitHub.

Of course, there's much more that you can dive into: official docs, tutorials, plugins, forum topics, etc. But my goal here was to prepare you for that journey with the must-know functionality of Filament.

I will continue creating content about Filament in other forms, so watch what's happening here on LaravelDaily.com or on my Twitter.

avatar

thanks Povilas, great course and really shows the massive power filament contains.

👍 2
avatar

Thx good work!

avatar
You can use Markdown
avatar

What to do if I would like to clone the github project?
command: git clone https://github.com/LaravelDaily/Filament3-Course-Main.git
command: composer install
command: npm install
configure .env with database
command: php artisan migrate:fresh --seed
command: php artisan serve

Is this enough or is something missing?

avatar

Should be enough, not sure about npm run dev or npm run build maybe.

avatar
You can use Markdown
avatar

Great course on a fantastic package Povilas! Thank you!

avatar
You can use Markdown
avatar

How to if the scenario was one user one role ? can these package restricted default behaviour ?

avatar

Not sure, could you ask this question to the package author on Github/Discord?

avatar

Why not remove the "multiple" from the select option? When editing or adding new users you only have the hability to select one role.

avatar
You can use Markdown
avatar

Good work👍

avatar
You can use Markdown
avatar

Liked this tutorial. easy to follow. Easy to copy and paste the code than when watching video. Video is good too once there is a text format like this to support it in which to easily see code differences and copy the code. Honestly i was able to breeze through it quickly than video. Text is also easier to update than video and can support many more languages than video.

avatar
You can use Markdown
avatar

Getting this error when i try to install filament shield:

composer require bezhansalleh/filament-shield "^3.0@beta" ./composer.json has been updated Running composer update bezhansalleh/filament-shield Loading composer repositories with package information Updating dependencies Your requirements could not be resolved to an installable set of packages.

Problem 1 - Root composer.json requires bezhansalleh/filament-shield 3.0@beta, found bezhansalleh/filament-shield[dev-main, dev-feature/performance-boost, v1.0.0, ..., 1.x-dev, v2.0.0, ..., 2.x-dev, 3.0.0-beta1, 3.0.0-beta2, 3.x-dev] but it does not match the constraint.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

avatar

Not sure, maybe something is wrong with other versions of your other packages? Could you open the issue on shield's GitHub? For me it worked, at the time of writing this course.

avatar
You can use Markdown
avatar

I noticed that even when you complete the Filament3 lessons, the progress bar never reaches 100%? Perhaps a bug thay needs to be fixed?

avatar

The bar is changing only if you click on the button below the lesson to go to the next lesson.

Maybe in some cases you just clicked the lesson on the sidebar on the right, then the system doesn't really know if you "finished" the current lesson or not.

avatar

Hi, I actually clicked from lesson to lesson from beginning to the end. I did actually think that what you mentioned was the case but I went back and clicked from lesson to lesson till the end and the percentage did not change. That was why I reported it.

avatar

Weird, need to reproduce it (somehow) and debug it. Thanks for reporting! P.S. There's also "Mark as completed" button on top but I guess no one clicks it :)

avatar

95 %, then click "Mark as completed" and ... 100%

avatar

I use the button on top. Very comfortably.

avatar
You can use Markdown
avatar

Is there a way to have a guest landing page of my products page. This would be where un-authenticated users can view the products list/detail but not edit or add anything? Also including all of the sort and search features.

avatar

You can use Filament Tables on a public Livewire page, yes. I'm adding to the list to write a tutorial about it, meanwhile here's an example how we used Filament FORMS on a Public page.

avatar
You can use Markdown
avatar

Hi Povilas, how to attach default role on user sign up?

avatar

We've just published a tutorial about it, just replace the 'role' string field with whatever logic you want.

avatar
You can use Markdown
avatar

Thank you very much for the course Povilas, I learned a lot directly from Brazil

👍 3
avatar
You can use Markdown
avatar

This type of text-based tutorial is definitely better than video in my opinion. Not only is it easier to follow through at my own pace (and skip over things I know) but it will also be much easier to refer back to specifc parts of the tutorial in the coming days/weeks.

avatar
You can use Markdown
avatar

In case I already use the php artisan shield:install and then add new modules, what command should I use to regenerate the permissions and roles

avatar
You can use Markdown
avatar

Thank you

avatar
You can use Markdown
avatar

Absolutely , No regret to purchase membership for livetime. very helpfull course.

avatar
You can use Markdown
avatar

filement shield Unknown column 'roles' in 'field list' error came when try add role from user adding page. Any soutions

avatar

You most likely missed ->relationship('roles') in your code. Hard to say without the code that you have

avatar
You can use Markdown
avatar

Great course. How do i handle user-specific data records. I have data records of different users in one table and of course i only want to allow access to the user's own rows. Do i save the user_id in the data records and filter accordingly? Do you have a tip or tutorial for that case?

avatar

Yes, this is so called "multi-tenancy" or a scoped query. You can take a look at our tutorial (keep in mind, it is a bit outdated!) to get an idea:

//post/simple-laravel-multi-tenancy-with-single-trait

avatar
You can use Markdown
avatar

Hi, i am trying to install filament breezy, //post/laravel-filament-12-best-plugins-with-demos I know, this tut is for filament v2. In v3 is no config/filament.php etc. I cant transfer it myself. Also the original docu of filament-breezy, i find hard for beginners. My question; "Using this package is very easy." also with v3? Now i am on step, Update the auth guard (Laravel 11, Filament 3.2.92)

avatar

Don't always follow the tutorial to the letter! In some cases, it's worth more to look into the package readme itself as it will have updated instructions. In this case, https://github.com/jeffgreco13/filament-breezy - has the required updated instructions for a v3 of Filament :)

avatar

I have done that and I will do it again. It doesn't seem to be as "very easy" with version 3 as described here with version 2 with 7 lines of code: //post/laravel-filament-12-best-plugins-with-demos :)

avatar

Things change :) But to be honest with you, a lot of stuff became more complicated (but also more powerful) with v3 ;)

avatar
You can use Markdown
avatar
Loganathan Natarajan

All in all, thanks for your detailed explanation

avatar
You can use Markdown
avatar

should the canAccessPanel method in the User class return false after the if statements?

avatar

You are right, we missed it! Updated :)

avatar
You can use Markdown
avatar

Hi, I'm implementing Laravel Shield with multiple authentication panels, each using different guards and user models. I took this course primarily for the last chapter covering Shield installation with multiple user types, but the implementation isn't working as expected since all users seem to use the same guard. Current Setup I have two separate panels:

Admin Panel

Panel name: 'admin' Uses "web" guard Users are in Admin model/table

Animator Panel

Panel name: 'anim' Uses "anim" guard Users are in Anim model/table

Issue Description The problem occurs right at the installation phase. After running php artisan shield:install, regardless of which panel I select, the generated "RolePolicy" file always uses the default User model: phpCopypublic function viewAny(User $user): bool { return $user->can('view_any_role'); } However, I don't have a "User" model in my application. When I proceed with php artisan shield:generate --panel, I get an error stating that the User model doesn't exist. Current Workaround I've found a temporary workaround by:

Manually publishing the config file Replacing 'fqcn' => 'App\Models\User' with 'fqcn' => 'App\Models\MYUSERMODEL'

However, this solution is incomplete because during policy generation, I can only have policies using either the "admin" model/guard OR the "anim" guard, but not both simultaneously. Question I feel I'm missing something fundamental in the setup process. Could someone explain the proper way to implement Laravel Shield with multiple panels using different guards and user models? Any guidance on the correct approach would be greatly appreciated.

🥳 1
avatar
You can use Markdown
avatar

You make it easy to understand. Thank you.

avatar
You can use Markdown
avatar
You can use Markdown