化学文摘社
此软件包允许集成 @casl/ability 与 第3组 应用。 因此,根据用户的能见度,可以显示或隐藏UI元素.
安装
npm install @casl/vue @casl/ability
# or
yarn add @casl/vue @casl/ability
# or
pnpm add @casl/vue @casl/ability
用于 Vue 2.x
npm install @casl/[email protected] @casl/ability
# or
yarn add @casl/[email protected] @casl/ability
# or
pnpm add @casl/[email protected] @casl/ability
开始
此软件包提供了 Vue 插件, 多个新钩子 Vue 组成 API 财务报告和审定财务报表 Can 组件.
插件
插件提供反应性 Ability 实例和可选定义 $ability 财务报告和审定财务报表 $can 全球属性,与Vue 2.x相同。 与上一个版本的唯一区别在于它要求 Ability 作为强制性论据而通过的案例:
import { createApp } from 'vue';
import { abilitiesPlugin } from '@casl/vue';
import ability from './services/ability';
createApp()
.use(abilitiesPlugin, ability, {
useGlobalProperties: true
})
.mount('#app');
以后我们也可以用 $ability 或者说 $can 任何组件中的方法 :
<template>
<div v-if="$can('create', 'Post')">
<a @click="createPost">Add Post</a>
</div>
</template>
globalProperties 同全球变量的概念一样,它可能使生命变得更加复杂,因为任何组件都能够访问它们(即隐含的依赖性),我们需要确保它们不会通过前缀引入名称相撞. 所以,与其揭露 $ability 财务报告和审定财务报表 $can 作为全球,我们可以使用 提供/输入 API 输入 $ability数字 :
createApp()
.use(abilitiesPlugin, ability)
.mount('#app');
并注入一个 Ability 在组件中,我们可以使用 ABILITY_TOKEN数字 :
<template>
<div>
<div v-if="$ability.can('create', 'Post')">
<a @click="createPost">Add Post</a>
</div>
</div>
</template>
<script>
import { ABILITY_TOKEN } from '@casl/vue';
export default {
inject: {
$ability: { from: ABILITY_TOKEN }
}
}
</script>
这更动词,但让我们可以明确。 这特别有用与新 组成 API数字 :
<template>
<div>
<div v-if="can('create', 'Post')">
<a @click="createPost">Add Post</a>
</div>
</div>
</template>
<script>
import { useAbility } from '@casl/vue';
export default {
setup() {
// some code
const { can } = useAbility();
return {
// other props
can
};
}
}
</script>
函数钩
很少,我们可能需要提供不同的 Ability 例如,组件的子树,为了做到这一点,我们可以使用 provideAbility 钩:
<template>
<!-- a template -->
</template>
<script>
import { provideAbility } from '@casl/vue';
import { defineAbility } from '@casl/ability';
export default {
setup() {
const myCustomAbility = defineAbility((can) => {
// ...
});
provideAbility(myCustomAbility)
}
}
</script>
见 CASL 指南 学习如何定义
Ability举个例子.
组件
我们可以用另一种方法来检查应用程序中的权限 Can 组件. Can 组件没有被插件注册,所以我们可以决定是否要使用组件 v-if + 键 $can 方法。 而且,这帮助树摇动 移除它 如果我们决定不使用它.
为了在全球注册组件,我们可以使用全球API(我们还可以在使用该组件的组件中在当地注册组件):
import { Can, abilitiesPlugin } from '@casl/vue';
createApp()
.use(abilitiesPlugin, ability)
.component(Can.name, Can) // component registration
.mount('#app');
这就是我们如何使用它:
<template>
<Can I="create" a="Post">
<a @click="createPost">Add Post</a>
</Can>
</template>
它接受默认槽和5个属性:
-
do- 动作名称(例如,read, (中文(简体) ),update) (中文(简体) ). 有别名I -
on- 检查对象。 有过a, (中文(简体) ),an, (中文(简体) ),this别名 -
field- 已检查的字段<template> <Can I="read" :this="post" field="title"> Yes, you can do this! ;) </Can> </template> -
not- 如果用户无法做一些动作, 反转能力检查并显示用户界面 :<template> <Can not I="create" a="Post"> You are not allowed to create a post </Can> </template> -
passThrough- 使儿童无论什么ability.can返回。 用于创建基于Can。例如,如果根据用户权限需要禁用按钮:<template> <div> <Can I="delete" a="Post" passThrough v-slot="{ allowed, ability, reason }"> <button :disabled="!allowed" :title="reason">Delete post</button> </Can> </div> </template>
财产名称和别名
从上面的代码中可以看出,组件名称及其属性名称和值产生了一个英文句子,实际上是一个问题. 上面的例子为"我能删除一个邮箱吗?".
还有其他几种财产别名可以构建一个可读问题。 这是帮助你的指南:
-
使用该
a(或an)按类型检查时的别名<Can I="read" a="Post">...</Can> -
使用情况
this当检查特定实例上的动作时,别名。 所以,这个问题可以读为"我可以读这个 特别 邮箱?"<Can I="read" :this="post">...</Can> -
使用情况
do财务报告和审定财务报表on如果你觉得无聊,不想让你的代码更容易读取:)<Can do="read" :on="post">...</Can> <Can do="read" :on="post" field="title">...</Can>
构成部分与反应能力
让我们考虑两种解决办法的ProS和CONS,以便作出决定.
反应能力数字 :
提议数字 :
- 易于使用
- 在模板中声明
v-if - 作为道具容易传递到另一个组件
- 易于用于复杂的布尔表达式(在js或模板中)
CONS (CONS) (英语)数字 :
- 检查费用比较高,每次重新检查都要重新评估条件
可组件数字 :
提议数字 :
- 声明
- 可以缓存权限检查结果直到道具或能力改变( 目前不)
CONS (CONS) (英语)数字 :
- 造价比较高
- 在模板中添加嵌入
- 在复杂的布尔表达式中更难使用
- 作为道具更难通过权限检查到另一个组件
尽管反应能力检查比较昂贵,但仍然非常快,建议使用反应能力代替 <Can> 组件.
类型脚本支持
软件包用TypeScript来写,所以不用担心你需要记住所有的属性和别名. 如果您使用 TypeScript, 您的 IDE 会建议您正确使用, 并且 TypeScript 会警告您如果出现错误 .
根据您的偏好,Vue app中使用TypeScript的方法很少. 但是,让我们首先定义我们的 AppAbility 类型 :
import { MongoAbility } from '@casl/ability';
type Actions = 'create' | 'read' | 'update' | 'delete';
type Subjects = 'Article' | 'User'
export type AppAbility = MongoAbility<[Actions, Subjects]>;
增强类型
TypeScript没有其他方法可以知道没有增强的全球属性类型. 要做到这一点,让我们补充 src/shims-ability.d.ts 带有下一个内容的文件 :
import { AppAbility } from './AppAbility'
declare module 'vue' {
interface ComponentCustomProperties {
$ability: AppAbility;
$can(this: this, ...args: Parameters<this['$ability']['can']>): boolean;
}
}
组成 API
配音API,我们不需要增加Vue类型,可以使用 useAbility 钩:
import { useAbility } from '@casl/vue';
import { AppAbility } from './AppAbility';
export default {
setup(props) {
const { can } = useAbility<AppAbility>();
return () => can('read', 'Post') ? 'Yes' : 'No';
}
}
此外,我们可以建立一个单独的 useAppAbility 钩子,所以我们不需要进口 useAbility 财务报告和审定财务报表 AppAbility 我们想要检查每个组件中的权限, 但只需导入一个单钩 :
import { useAbility } from '@casl/vue';
import { AppAbility } from '../AppAbility';
export const useAppAbility = () => useAbility<AppAbility>();
选项 API
也可以用到这个 @casl/vue 和带有选项 API 的脚本。 默认, ABILITY_TOKEN 输入为 InjectionKey<Ability>,将它投给 InjectionKey<AppAbility>,我们需要使用单独的变量:
import { InjectionKey } from 'vue';
import { ABILITY_TOKEN } from '@casl/vue';
// previous content that defines `AppAbility`
export const TOKEN = ABILITY_TOKEN as InjectionKey<AppAbility>;
现在,当我们注射 AppAbility 例如,我们将有正确的类型:
<script lang="ts">
import { defineComponent } from 'vue';
import { TOKEN } from './AppAbility';
export default defineComponent({
inject: {
ability: { from: TOKEN }
},
created() {
this.ability // AppAbility instance
}
});
</script>
读取 Vue 类型脚本 详情
更新能力实例
需要权限检查支持的应用程序大多有类似的东西 AuthService 或者说 LoginService 或者说 Session 服务(按您的意愿命名),负责用户登录/登录功能。 每次用户登录(和登录),我们需要更新 Ability 以新规则为例。 通常你会这样做 在你的 LoginComponent。 。 。 .
让我们想象一下,服务器返回的用户在登录上有一个角色:
<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>
import { AbilityBuilder, createMongoAbility } from '@casl/ability';
import { ABILITY_TOKEN } from '@casl/vue';
import { AppAbility } from '../ability';
export default {
name: 'LoginForm',
inject: {
$ability: { from: ABILITY_TOKEN }
},
data: () => ({
email: '',
password: ''
}),
methods: {
login() {
const { email, password } = this;
const params = { method: 'POST', body: JSON.stringify({ email, password }) };
return fetch('path/to/api/login', params)
.then(response => response.json())
.then(({ user }) => this.updateAbility(user));
},
updateAbility(user) {
const { can, rules } = new AbilityBuilder<AppAbility>(createMongoAbility);
if (user.role === 'admin') {
can('manage', 'all');
} else {
can('read', 'all');
}
this.$ability.update(rules);
}
}
};
</script>
见 定义规则 获取更多关于如何定义的信息
Ability。 。 。 .
想帮忙吗?
想要提交错误, 提供一些代码, 还是改进文档 ? 不错! 阅读指南 捐款。 。 。 .
如果你想帮助我们 维持我们的社区和项目,考虑 成为开放集体的出资人
见 支助CASL 详细情况.