DEV Community

Cover image for How to use Laravel Permission by Spatie in Vue
George Tudor
George Tudor

Posted on • Updated on

How to use Laravel Permission by Spatie in Vue

UPDATE: You can do the same as below using this package geowrgetudor/laravel-spatie-permissions-vue. It is a fork I made from the original package. Adds support for server-side rendering (SSR) and doesn't require installing a npm package (everything is built in).


When in comes to Laravel packages, the guys at Spatie are probably the kings. They have hundreds of free packages you can pick from and use into your projects. Hats down for their commitment and contribution to this beautiful ecosystem.

Now let's talk about permissions because if you're building a large Laravel app you definitely gonna need them. As a quick example, let's think of an admin panel built with Vue that needs different user roles where each role has specific permissions.

Of course you can build all this functionality yourself, but why reinvent the wheel? There's a neat package from Spatie called spatie/laravel-permission which makes things really simple.

Installation and setup

All you have to do is to install it and do a bit of configuration like publishing the vendor files (config and migration) plus some trait:

composer require spatie/laravel-permission

# Publish the vendor's config file and migration
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

# Clear your config cache so the package can pick up the published filed
php artisan config:clear

# Run the migration
php artisan migrate
Enter fullscreen mode Exit fullscreen mode

The next step is to add the package's trait to your user model and you're ready to roll:

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}
Enter fullscreen mode Exit fullscreen mode

By default, the package comes with a super-admin role published into your database by the default migration. You can use that of course, but you also can add your own roles and permissions.

Adding new roles and permissions

So let's create 2 roles and assign them some permissions. You can do this in a migration, seeder, artisan command, some UI interface, whatever suits you best.

The package comes with some premade artisan commands you can use to create roles and permissions (you can check their docs for that), but for the sake of this demo, I'm going to use tinker.

# Create an editor role
$roleEditor = \Spatie\Permission\Models\Role::create(['name' => 'editor']);

# Create a supervisor role
$roleSupervisor = \Spatie\Permission\Models\Role::create(['name' => 'supervisor']);


# Now lets create permissions and assign them to our freshly created roles
$permissions = [
    'can-view-posts',
    'can-edit-posts',
    'can-publish-posts',
    'can-deleted-posts',
    'can-view-activity',
    'can-export-activity'
];

foreach($permissions as $permissionName) {
    $permission = \Spatie\Permission\Models\Permission::create(['name' => $permissionName]);

    if(in_array($permissionName, ['can-view-posts', 'can-edit-posts', 'can-publish-posts', 'can-deleted-posts'])) {
        $roleEditor->givePermissionTo($permission);
    } else {
        $roleSupervisor->givePermissionTo($permission);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, that we have all the permissions in place for each role, we can start using them in our controllers, services, routes, templates, etc.

Let's talk about templates

By default, this package comes with some handy Blade directives. You can use @can, @role, @hasrole, @hasanyrole and many more directives to render whatever you need based on roles and permissions. This is great, but these are only available in Blade.

How can we create something similar in Vue? The process will be like this:

  1. We need to expose all the roles and permissions to the frontend
  2. We need to defines some similar functions

Luckily, you don't have to do this from scratch. You can use laravel-permission-to-vuejs which is a javascript package and ahmedsaoud31/laravel-permission-to-vuejs which is a composer package. These 2 packages are great and are exactly what we need to use the same roles and permissions into our Vue application.

First, we need to install the server side package and add another trait to our User model:

composer require ahmedsaoud31/laravel-permission-to-vuejs=dev-master
Enter fullscreen mode Exit fullscreen mode

Now lets add the trait:

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use LaravelAndVueJS\Traits\LaravelPermissionToVueJS;

class User extends Authenticatable
{
    use HasRoles;
    use LaravelPermissionToVueJS;
}
Enter fullscreen mode Exit fullscreen mode

Next, we'll need to expose the roles and permissions to the frontend. To do this we need to attach a Laravel property to the window. You can add this code into your main Blade template which loads everything for your frontend:

<script type="text/javascript">
    window.Laravel = {
        csrfToken: "{{ csrf_token() }}",
        jsPermissions: {!! auth()->user()?->jsPermissions() !!}
    }
</script>
Enter fullscreen mode Exit fullscreen mode

The last step is to install the Vue javascript package, which also supports Vue 3:

npm install --save laravel-permission-to-vuejs

# Instruct Vue to use it
// ...
import LaravelPermissionToVueJS from 'laravel-permission-to-vuejs'

const app = createApp(App)
app.use(LaravelPermissionToVueJS)
// ...
Enter fullscreen mode Exit fullscreen mode

Now we can use similar functions to Spatie's blade directives like can() to check for a specific permission and is() to check for specific roles. Here's a short example:

<div v-if="can('can-view-posts')">
    Only users with this permission can view this DIV.
</div>

<div v-if="is('supervisor')">
    Only users with this role can view this DIV.
</div>
Enter fullscreen mode Exit fullscreen mode

We can also pass multiple permissions or roles to check against. Example: can('can-view-posts | can-edit-posts').

That's pretty much it. Now you can enjoy using the same permissions you are using in the backend without creating a lot of mess in your Vue templates.

Support & follow me

Buy me a coffee Twitter GitHub Linkedin

Latest comments (4)

Collapse
 
developeralam profile image
Md Alam

Image description


Enter fullscreen mode Exit fullscreen mode
Collapse
 
geraldmacasaet profile image
Gerald Macasaet

It's working for me but you need to refresh the page for it to work. If for instance you log in as another user role, log out, and log back in as another user role, the role and permissions seems to not refresh.

Collapse
 
jimmyazji profile image
jimmy • Edited

Probably late but I fixed this issue with:

in addition to using:

<script type="text/javascript">
window.Laravel = {
csrfToken: "{{ csrf_token() }}",
jsPermissions: {!! auth()->check()?auth()->user()->jsPermissions():0 !!}
}
</script>

in app.js

axios.get('/get-permissions').then(
response => {
window.Laravel.jsPermissions = response.data;
}
);

in laravel route

Route::get('/get-permissions', function () {
return auth()->check()?auth()->user()->jsPermissions():0;
});

As the issue comes from the permissions being loaded on the first time you load a page only.
With this solution every time you visit a route you call a get-permissions api and check for the permissions, also you might consider only refreshing the permissions on login or somehow call the api only when needed to increase the performance although I don't really think its that important.

This method is mentioned in the package Readme here

Collapse
 
developeralam profile image
Md Alam

not working in composition api