Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

sl0wik's avatar

Roles and permissions in vue

Hi guys,

I know this subject was touched previously but I still have difficulties with finding a good way to deal with roles and permissions in Vue.

Assuming roles and permissions are stored in standard $user->roles and $user->permissions, what would be the best way to deal with them in Vue?

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()
            ]); ?>

but than how to do verification without too much coupling. Any suggestions?

0 likes
9 replies
cfort's avatar
cfort
Best Answer
Level 8

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;
})
<button v-can="editStuff">You can edit this thing</button>

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

7 likes
topvillas's avatar

That would do it but you'd need to do something to the element. Hide it or set it's disabled attribute, maybe.

Could get complicated if you wanted to handle each element type by case.

EDIT: I just looked at the docs and noticed the binding has a modifiers property which could specify what to do if you don't have permission.

<button v-can:disable="editStuff">

sl0wik's avatar

There is one issue with this approach. For example, while having comments table, user always have permission to edit his comments. Component should know if author_id is equal user_id.

I made a very simple plugin (components/plugins/acl.js) to deal with it:

/*
* Simple plugin adding $can method to Vue.
* Require permissions loaded in window.Laravel.permissions and current userId in window.Laravel.userId
*/

const Acl = {
    install(Vue, options) {
        // If authorID id is equal to current userId permission is always granted
        Vue.prototype.$can = function (permission, authorId = false) {
            if (window.Laravel.userId == authorId) {
                return true;
            }
            if (window.Laravel.permissions.indexOf(permission)!==-1) {
                return true;
            }
        }
    }
};

module.exports = Acl;

Than:

Vue.use(require('./components/plugins/acl.js'));

Than inside component use for example if (this.$can('comments.edit')) ... or something like this.$can('comments.edit', this.author.id).

1 like
sl0wik's avatar

Sorry for pasting. This one includes simple can directive, that supports authorId parameter (optional).

Quick and simplefied code:

/*
* Simple plugin adding $can method to Vue.
* Require permissions loaded in window.Laravel.permissions and current userId in window.Laravel.userId
*/

const Acl = {
    install(Vue, options) {
        // "can" directive accept string with single permission or object containing "permission", and "authorId"
        Vue.directive('can', {
            bind (el, binding, vnode, oldVnode) {
                if (binding.value instanceof Object) {
                    if (binding.value.authorId==window.Laravel.userId) {
                        return true;
                    }
                    permission = binding.value.permission;
                } else {
                    permission = binding.value;
                }
                if (window.Laravel.permissions.indexOf(permission)==-1) {
                    el.style.display = 'none';
                }
            }
        });
        // If authorID id is equal to current userId permission is always granted
        Vue.prototype.$can = function (permission, authorId = false) {
            if (window.Laravel.userId == authorId) {
                return true;
            }
            if (window.Laravel.permissions.indexOf(permission)!==-1) {
                return true;
            }
        }
    }
};

module.exports = Acl;
2 likes
Holm's avatar

Really nice solution Leber

xsmalbil@icloud.com's avatar

@leber, @Holm, @cfort

If any of you uses vuex getters and lodash, then you might find my snippet helpfull:


/**
 * Check if an user has a role & returns true or false
 * usage: has('Admin')
 */
export const has = state => role => {
    return state.role == role;
};

/**
 * Check if an user has a permission & returns true or false
 * usage: can('modify.user')
 */
export const can = state => permission => {
    return _.find(state.permissions, function(n) {
        return _.matches(permission)(n);
    });
};

You will import these getters in your .vue file like in this example:



export default {

    computed: {
        ...getters({
          can,has
        })
    }
};


And use them in your template like in this example:


<div>
    <button v-if="can('client.update.active-status')">Activate</button>
    <button v-if="can('client.update.active-status')">Deactivate</button>
    <button v-if="can('client.delete')">Delete</button>
    <button v-if="can('client.export')">Export</button>
</div>


I return the permissions from Laravel into the html meta, just like the csrf tokens are done usually. But I base64 encode the permissions before I push them to the view.

Then I retrieve it like this:


// RBAC
let rbac = document.head.querySelector('meta[name="rbac"]');

/*
  Store modules:

  Register here OR register somewhere else, when getters start biting or whatever.
  example:  this.$store.registerModule('interface',    InterfaceStoreModule);
*/
store.registerModule("rbac", RBACStoreModule);
store.dispatch("setRBAC", rbac.content);


I have some helpers for the decoding when commiting the permissions to the store.


// From String to Base-64
window.base64Encode = obj => {
    return btoa(JSON.stringify(obj));
};
// To decode back to actual
window.base64Decode = obj => {
    return JSON.parse(atob(obj));

1 like
Bonbonzone's avatar
Vue.prototype.$can = function (permission, authorId = false) {
            if (window.Laravel.userId == authorId) {
                    return true;
            ...

So if the userId is not set, it will always return true?

Please or to participate in this conversation.