Casl/vue $can function is returning false, but user has that permission

Viewed 1610

I am using @casl/vue plugin for user permissions management in vue cli project as shown in this sample repo by casl plugin author sample(vue-blog). Here is my code
ability.js

export default (store) => {
const ability = store.getters.ability
ability.update(store.state.rules);
return store.subscribe((mutation) => {
    switch (mutation.type) {
        case 'ROOT_LOGIN_SUCCESS':
            var formattedRules = [];
            if (mutation.payload.permissions.length > 0) {
                formattedRules = mutation.payload.permissions.map(perm => {
                    let formattedObj = {};
                    formattedObj.actions = perm.substr(0, perm.indexOf(' '));
                    formattedObj.subject = perm.substr(perm.indexOf(' ') + 1);
                    return formattedObj;
                })
            }
            console.log(formattedRules)
            ability.update(formattedRules);
            break
        case 'ROOT_LOGOUT_SUCCESS':
            ability.update([{actions: 'read', subject: 'all'}])
            break
    }
 })
}

I am getting rules from rest-api on login and formatting and saving it to localStorage in casl/vue format {actions: 'someAction', subject: 'someSubject'}. Here is
storage.js

export default (options) => (store) => {
 if (localStorage.state) {
    const storedState = JSON.parse(localStorage.state)
    store.replaceState(Object.assign(store.state, storedState))
 }
 return store.subscribe((mutation, state) => {
    if (options.destroyOn && options.destroyOn.indexOf(mutation.type) !== -1) {
        return localStorage.removeItem('state')
    }
    const newState = options.storedKeys.reduce((map, key) => {
        map[key] = state[key]
        return map
    }, {});
    localStorage.state = JSON.stringify(newState)
 })
}


and store.js

/*
 * FOR USER PERMISSIONS MANAGEMENT ON UI */
 import {Ability} from '@casl/ability'
 import abilityPlugin from "@/shared/store/ability"
 import storage from "@/shared/store/storage";
 ...
 export default new Vuex.Store({
    plugins: [
      storage({
        storedKeys: ['token', 'rules'],
        destroyOn: ['ROOT_LOGOUT_SUCCESS']
      }),
      abilityPlugin
    ],
 ...
 mutations: {
    ROOT_LOGIN_SUCCESS(state, data) {
        let formattedRules = [];
        if (data.permissions.length > 0) {
            formattedRules = data.permissions.map(perm => {
                let formattedObj = {};
                formattedObj.actions = perm.substr(0, perm.indexOf(' '));
                formattedObj.subject = perm.substr(perm.indexOf(' ') + 1);
                return formattedObj;
            })
        }
        state.rules = formattedRules;
        state.token = data.token;
    },
    ROOT_LOGOUT_SUCCESS(state) {
        state.rules = [];
    },
 },
 ...
 getters: {
     ability() {
         return new Ability()
     }
  },
}

main.js

/*
* FOR USER PERMISSIONS MANAGEMENT ON UI */
 import {abilitiesPlugin, Can} from '@casl/vue'
 Vue.use(abilitiesPlugin, store.getters.ability)
 Vue.component('Can', Can);

Inside Vue component template I am using it like this
index.vue

          <v-btn
            v-if="$can('delete', 'department')"
            color="error"
            dark
            @click="uiShowConfirm({content: 'Are you sure?', 
                     callBack: deleteConfirmed})"
        >
            <v-icon class="mr-2">mdi-delete</v-icon>
            Delete
        </v-btn>

But it is returning false
Some help is really appreciated!
I have saved rules like this enter image description here

1 Answers

I was using @casl/ability@5.2.2 and @casl/vue@1.2.2
As said in the comments by @SergiiStotskyi

If you get null for relevantRuleFor it means that casl doesn’t a rule for provided action/subject pair. From what I can tell is that the shape of rule object is wrong. actions was deprecated in v4 and removed in v5. Try to replace actions with action

After changing actions to action that worked.

Thanks @SergiiStotskyi
Casl is a great library

Related