Search code examples
vuejs3casl

CASL-Vue Can component hides components for both authorized and unauthorized user


I have a component that I'll like to show if user has permission but the Can component seem to hide the component regardless of user permission.

Following is my ability.js module

import {Ability, AbilityBuilder} from "@casl/ability";

export default function defineAbilityFor(hasRole) {
    const { can, cannot, build } = new AbilityBuilder(Ability)
    if (hasRole !== undefined) {
        console.log(hasRole)
        can('manage', 'all')
        can('create', 'all')
    } else {
        can('read', 'all')
        cannot('create', 'all')
    }

    return build()
}

I added castle as a my main.js as follows:

const app = createApp(App)
app.use(router)
app.use(store)
app.use(abilitiesPlugin, ability(), {
    useGlobalProperties: true
})
app.component(Can.name, Can)
app.mount('#app')

And the following is the component in which i need to do permission check.

<template>
  <div class="d-flex flex-column px-4">
    <div class="d-flex justify-content-end">
      <Can I="create" an="Institution">
        <button class="btn btn-sm btn-outline-success" @click="addInst = true">{{ action }}</button>
      </Can>
    </div>
    <ListInstitutions v-if="addInst === false"/>
    <Can I="create" an="Institution">
      <AddInstitution v-if="addInst === true" @created="closeModal"/>
    </Can>
  </div>
</template>

<script>
import AddInstitution from "@/components/institution/AddInstitution";
import ListInstitutions from "@/components/institution/ListInstitutions";
import { Can } from "@casl/vue";

export default {
  name: 'InstitutionPage',
  components: {AddInstitution, ListInstitutions, Can},
  data() {
    return {
      addInst: false,
      action: this.addInst ? 'Institutions' : 'Add Institution'
    }
  },
  methods: {
    closeModal() {
      this.addInst = false
    }
  }
}
</script>


Solution

  • Thank you so much @Sergii Stotskyi.

    I eventually defined ability in a definedAbility.js file as follows:

    import { AbilityBuilder, Ability } from "@casl/ability";
    
    export default function defineAbilityFor(userRole) {
      const { can, cannot, build } = new AbilityBuilder(Ability);
    
      if (userRole === 'user') {
        can ('read', 'Institution')
        cannot(['create', 'update'], 'all')
      }
    
      if (userRole === 'reg_admin_stroke' || userRole === 'admin') {
        can('manage', 'all')
      }
    
      return build()
    }

    And then in every component where ability is required, inside the setup() method I create the ability as follows:

    ...
    import definedAbility from '@/services/definedAbility.js'
    
    ...
    const ability = definedAbility(userRole.value)
    
    return {
      ability
    }

    And In my template did something like:

    <div v-if="ability.can('create', 'Institution')">
       <button class="btn btn-sm btn-outline-success"                           @click="addInst = true">{{ action }}</button>
    </div>