9

I am in the process of integrating Laravel Permission API with Vue.JS frontend. I am using https://github.com/spatie/laravel-permission library for Laravel Permission. I am not understanding how can I check permission in the Vue JS front End (In Laravel blade I am using @Can to check the permission).

1
  • I am also facing the same problem. Commented Nov 15, 2018 at 5:25

5 Answers 5

10
+50

I will do a ajax call to check for permissions instead , something like this, but of cours eyou need to modify it to cater your needs.

Routes:

Route::get('/permission/{permissionName}', 'PermissionController@check');

Controller:

function check($permissionName) {
   if (! Auth::user()->hasPermissionTo($permissionName)) {
        abort(403);
   }
   return response('', 204);
}

Vue: (if you wanna do this synchronously), this is a simple example (Vue global mixin), you can turn this into Vue directive or component.

Vue.mixin("can", (permissionName) => {
    let hasAccess;
    axios.get(`/permission/${permissionName}`)
        .then(()=> {
            hasAccess = true;
        }
        .catch(()=> {
            hasAccess = false;
        };
    return hasAccess;
});

And then everytime you wanna check permission, you can just do

<el-input v-if="can('write-stuff')"> </el-input>
6
  • 16
    Imagine you have 100 buttons on the page. And you entering the page... Boom 100 axios get requests. I think it's a bad practice. Commented Jan 28, 2020 at 12:58
  • 1
    @IvanDavletshin That is true, but in that case, you should just put the v-if on the common div that holds these 100 buttons
    – Shuyi
    Commented Feb 24, 2020 at 23:30
  • 1
    But that works only if the v-if is the same for all the buttons. And that can be cached somehow as well to be able to place buttons, not in only one div. But what if the ability should be different from button to button. I'm implementing now cancan-like integration into Laravel and Vue sides. So they both will have the same rules. That's for me looks much more correct. Commented Feb 26, 2020 at 3:12
  • Hi Shuyi, how to hide the element if no access to the element? Commented Sep 28, 2020 at 7:06
  • 1
    This won't work as the get request is an async operation. Returning hasAccess will just yield undefined. If you use async/await in the mixin, it will just return a Promise instead of resolving. Commented May 9, 2021 at 9:47
5

I'm literally working on this exact same thing. I'm thinking of adding a custom Vue directive that would check against the Laravel.permissions array.

It might even be as simple as

 Vue.directive('can', function (el, binding) {
  return Laravel.permissions.indexOf(binding) !== -1;
})

I haven't tested this code. Just brainstorming here.

<button v-can="editStuff">You can edit this thing</button>

I can hold permissions this way:

window.Laravel = <?php echo json_encode([
                'csrfToken' => csrf_token(),
                'userId' => Auth::user()->id,
                'permissions' => Auth::user()->permissions()->pluck('name')->toArray()
            ]); ?>
6
  • How you get laravel permission array in vue js? Commented Nov 15, 2018 at 5:56
  • 2
    I guess you'd just use <script type="text/javascript"> window.Laravel = { permissions: Json.parse('@json(\Auth::user()->permissions)') };</script> somewhere in a blade template (most likely layout.blade.php).
    – Namoshek
    Commented Feb 8, 2019 at 10:22
  • 4
    I think you're going to want to set up an endpoint that you can hit from the vue front end that will give you the user permissions back, otherwise, in the example above, what prevents a user from editing their permissions and gaining access to everything.
    – whmkr
    Commented Feb 11, 2019 at 17:40
  • 2
    @wheelmaker this would not matter as everything that requires a permission would still be behind an endpoint, its just for the frontend layout Commented Feb 11, 2019 at 21:36
  • is it secure way to use ?
    – Zia
    Commented Feb 11, 2021 at 5:38
2

Just stumbled upon this problem and I would like to share what I found and implemented.

  1. Add an accessor on the User model the spatie/laravel-permission is using
    public function getAllPermissionsAttribute() {
       $permissions = [];
         foreach (Permission::all() as $permission) {
           if (Auth::user()->can($permission->name)) {
             $permissions[] = $permission->name;
           }
         }
       return $permissions;
    }
  1. On your global page or layout page pass the permission from the accessor to the javascript.
    <script type="text/javascript">
       @auth
          window.Permissions = {!! json_encode(Auth::user()->allPermissions, true) !!};
       @else
          window.Permissions = [];
       @endauth
    </script>
  1. Create a global directive on resources/js/app.js
    Vue.directive('can', function (el, binding, vnode) {

        if(Permissions.indexOf(binding.value) !== -1){
           return vnode.elm.hidden = false;
        }else{
           return vnode.elm.hidden = true;
        }
    })

Here you are checking if the permission you supplied on the directive is on the permission array from laravel. If found then it will hide the element else show, this function is like a v-if.

  1. Use it like this on your component - "add_items" is your permission
    <button type="button" v-can="'add_items'"></button>

This solution is from this but instead of a mixin, I use a directive. Got the idea of directive from @Ismoil Shifoev comment above.

2
  • 1
    The problem with this is that in a SPA the permissions are not updated with every request to the server. Therefore window.Permissions will always be empty. So if you are logged out and then log in, the permissions will remain empty and you will not have access to anything.
    – MrEduar
    Commented Mar 4, 2022 at 13:10
  • As MrEduar pointed out, there is an issue with not changing permissions after login. I've applied a solution to reload dashboard after every login. What is the best practice?
    – user109764
    Commented Oct 6, 2022 at 21:51
1

You can use this format in Vuejs for Laravel Permission:

<div v-if="can('edit post')">
  <!-- Edit post form -->
</div>

<div v-if="is('super-admin')">
  <!-- Show admin tools -->
</div>

add function to User Model to get all user permissions&roles like this:

class User extends Authenticatable
{
    // ...

    public function jsPermissions()
    {
        return json_encode([
                'roles' => $this->getRoleNames(),
                'permissions' => $this->getAllPermissions()->pluck('name'),
            ]);
    }
}

pass this data to JavaScript in HTML header:

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

in app.js file add global Vuejs can function to check user permissions and is function to check user roles:

Vue.prototype.can = function(value){
    return window.Laravel.jsPermissions.permissions.includes(value);
}
Vue.prototype.is = function(value){
    return window.Laravel.jsPermissions.roles.includes(value);
}

https://github.com/ahmedsaoud31/laravel-permission-to-vuejs

2
  • The problem with this is that in a SPA the permissions are not updated with every request to the server. Therefore window.Permissions will always be empty. So if you are logged out and then log in, the permissions will remain empty and you will not have access to anything.
    – MrEduar
    Commented Mar 4, 2022 at 13:10
  • As MrEduar pointed out, there is an issue with not changing permissions after login. I've applied a solution to reload dashboard after every login. What is the best practice?
    – user109764
    Commented Oct 6, 2022 at 22:07
0

I would go with Ralph solution. But I find myself better using. This function to fetch the Permissions.

public function getAllPermissionsAttribute() {
    return Auth::user()->getAllPermissions()->pluck('name');
}

Just a bit cleaner, and since I tend to use Roles instead of particular permissions for each User, this solution should work as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.