How to use Laravel Permission by Spatie in Vue
Tags: laravel, spatie, permission, vue
Published: 2022-10-31 09:44:10

**UPDATE:** You can do the same as below using this package [geowrgetudor/laravel-spatie-permissions-vue](https://github.com/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](https://spatie.be/) 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](https://spatie.be/docs/laravel-permission/v5/introduction) 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
```

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;
}
```

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);
    }
}
```

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](https://www.npmjs.com/package/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
```

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;
}
```

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>
```

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)
// ...
```

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>
```

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](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/geowrgetudor) | [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/geowrgetudor) | [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/geowrgetudor) | [![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://linkedin.com/in/geowrgetudor) |
| ------------- | ------------- | ------------- | ------------- |