第 7 章 前端权限控制:按钮该不该显示
本文导航

第 7 章 前端权限控制:按钮该不该显示
后端负责「能不能做」,前端负责「让不让人看见」。这一章说明 owl-ui 提供的两种权限工具,以及它们的区别。
权限数据从哪来
登录后,前端会:
- 保存
accessToken; - 调用
/users/me/permissions获取权限标识; - 写入 Pinia 的
useUserStore().permissions; - 缓存到 localStorage,TTL 24 小时。
超管拿到的权限是 ["*:*:*"]。
方式一:hasPerms(推荐)
import { hasPerms } from "@bit-labs.cn/owl-ui";
const canCreate = hasPerms("admin:user:Create");
实现逻辑:
export const hasPerms = (value: string | Array<string>): boolean => {
if (!value) return false;
const allPerms = "*:*:*";
const { permissions } = useUserStoreHook();
if (!permissions) return false;
if (permissions.length === 1 && permissions[0] === allPerms) return true;
const isAuths = isString(value)
? permissions.includes(value)
: isIncludeAllChildren(value, permissions);
return isAuths;
};
要点:
- 字符串:包含即通过;
- 数组:要求全部包含才通过;
- 超管通配符
*:*:*直接通过; - 比较的是后端返回的权限标识,必须完全一致。
在模板里用
<script setup lang="ts">
import { hasPerms } from "@bit-labs.cn/owl-ui";
</script>
<template>
<el-button
v-if="hasPerms('admin:user:Create')"
type="primary"
@click="openCreate"
>
新建用户
</el-button>
</template>
用 Perms 组件
<script setup lang="ts">
import { Perms } from "@bit-labs.cn/owl-ui";
</script>
<template>
<Perms value="admin:user:Create">
<el-button type="primary">新建用户</el-button>
</Perms>
</template>
Perms 内部就是 hasPerms,通过则渲染插槽,否则不渲染。
方式二:v-auth / Auth(基于路由 meta)
owl-ui 还提供了:
<el-button v-auth="'btn.add'">新增</el-button>
<Auth value="btn.add">
<el-button>新增</el-button>
</Auth>
它们底层是 hasAuth:
function hasAuth(value: string | Array<string>): boolean {
const metaAuths = router.currentRoute.value.meta.auths;
if (!metaAuths) return false;
return isString(value)
? metaAuths.includes(value)
: isIncludeAllChildren(value, metaAuths);
}
区别:
hasPerms / Perms |
hasAuth / v-auth / Auth |
|
|---|---|---|
| 数据源 | 登录接口返回的 permissions |
当前路由 meta.auths |
| 适合 | 后端权限标识 | 前端静态配置的按钮编码 |
| 当前后台 | 菜单数据不含 auths |
需要自己在路由 meta 里填 |
结论:对接 owl-admin 的后端权限时,用 hasPerms 或 Perms。v-auth 更适合前端自己定义一套与后端无关的页面内编码。
权限标识必须与后端一致
前端写:
hasPerms("admin:user:Create");
后端按钮菜单携带:
admin:user:Create
大小写、冒号、方法名都要一致。最常见的错误是前端写路由名 user:create 或中文标题。
隐藏按钮不等于安全
前端隐藏只是体验:
用户看不到按钮 ≠ 用户不能调接口
真正的边界在 PermissionCheck 中间件。如果只做前端隐藏、接口仍是 AccessAuthenticated,用户完全可以手工调接口。
正确组合:
- 路由用
AccessAuthorized; - 角色分配对应按钮菜单;
- 前端用
hasPerms隐藏按钮。
常见问题
超管看不到按钮
检查 permissions 是否包含 *:*:*。超管登录后应调用权限接口并写入 store;如果用了旧缓存,清掉 localStorage。
普通用户菜单正常,按钮全没了
按钮菜单没有分配给角色,或前端缓存的权限是空的。先查 /users/me/permissions。
权限改了,页面没变
前端缓存 24 小时。重新登录,或调用 fetchAndCachePermissions() 刷新。
数组写法不生效
hasPerms(["a", "b"]) 要求两个权限都有。只想满足其一,用 hasPerms("a") || hasPerms("b")。
自检
- [ ] 知道
hasPerms的数据来自/users/me/permissions; - [ ] 知道数组是「全部满足」;
- [ ] 知道
v-auth依赖路由meta.auths,与后端权限标识不是一回事; - [ ] 前端隐藏的同时,后端接口级别正确;
- [ ] 能处理权限缓存导致的「按钮不更新」。
评论
加载评论中…