This package allows integrating @casl/ability into a Vue application. So, you can show or hide UI elements based on user ability to see them.
npm install @casl/vue @casl/ability
This package provides a Vue plugin which defines $ability
object and $can
method for all components
import { abilitiesPlugin } from '@casl/vue'
import Vue from 'vue'
Vue.use(abilitiesPlugin)
By default, the $ability
object is an empty Ability
instance. So you either need to update it or provide your own.
In case you want to provide your own, just define it using AbilityBuilder
or whatever way you prefer:
// ability.js
import { AbilityBuilder } from '@casl/ability'
export default AbilityBuilder.define(can => {
can('read', 'all')
})
And just pass it as an argument to abilitiesPlugin
:
import { abilitiesPlugin } from '@casl/vue'
import Vue from 'vue'
import ability from './ability'
Vue.use(abilitiesPlugin, ability)
Alternatively, you can just update an existing instance, for example, in the SignIn.vue
component when receiving a rules list from a server API (or other sources).
<template>
<form @submit.prevent="login">
<input type="email" v-model="email" />
<input type="password" v-model="password" />
<button type="submit">Login</button>
</form>
</template>
<script>
export default {
name: 'SignIn',
data: () => ({
email: '',
password: ''
}),
methods: {
login() {
const { email, password } = this
return fetch('path/to/api/login', { method: 'POST', body: JSON.stringify({ email, password }) })
.then(response => response.json())
.then(session => this.$ability.update(session.rules))
}
}
}
</script>
Obviously, in this case your server API should provide the list of user abilities in the rules
field of the response.
See the @casl/ability package for more information on how to define abilities.
To check permissions in any component you can use the $can
method:
<template>
<div v-if="$can('create', 'Post')">
<a @click="createPost">Add Post</a>
</div>
</template>
See casl-vue-example and casl-vuex-example for more examples.
Another way to provide an Ability
instance is to pass it as option into your root component:
// main.js
import App from './App'
import ability from './ability'
new Vue({
store,
router,
ability,
render: h => h(App)
}).$mount('#app')
That instance will be available under the $ability
property, and the $can
method will use it to check permissions.
That way, you can also provide a different ability for a component's subtree.
// TodoList.vue
<template>...</template>
<script>
import { AbilityBuilder } from '@casl/ability'
export default {
name: 'TodoList',
ability: AbilityBuilder.define(can => {
...
})
}
</script>
Note: I don't recommend trying to manage more than one Ability
instance in the app
because this contradicts to the main goal of CASL: keep all permissions in a single place and manage them from the single location (Ability
instance).
There is an alternative way you can check your permissions in the app by using the Can
component. To enable this feature you need to register it globally:
import Vue from 'vue'
import { Can } from '@casl/vue'
Vue.component('Can', Can)
Now, instead of using v-if="$can(...)"
, we can do this:
<template>
<can I="create" a="Post">
<a @click="createPost">Add Post</a>
</can>
</template>
As you can see from the code above, the component name and its property names and values create an English sentence, basically a question.
For example, the code above reads as Can I create a Post
.
There are several other property aliases which allow constructing a readable question:
- use the
a
alias when you check by Type
<Can I="read" a="Post">...</Can>
- use the
of
alias instead ofa
when you check by subject field
<Can I="read title" of="Post">...</Can>
<!-- or when checking on instance. `post` is an instance of `Post` class (i.e., model instance) -->
<Can I="read title" :of="post">...</Can>
- use the
this
alias instead ofof
anda
when you check action on instance
<!-- `post` is an instance of `Post` class (i.e., model instance) -->
<Can I="read" :this="post">...</Can>
- use
do
andon
if you are bored and don't want to make your code more readable :)
<!-- `post` is an instance of `Post` class (i.e., model instance) -->
<Can do="read" :on="post">...</Can>
<!-- or per field check -->
<Can do="read title" :on="post">...</Can>
- use
not
when you want to invert the render method (renders children only if user can't read a post)
<Can not I="read" a="Post">...</Can>
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on guidelines for contributing