import{_ as i,o as a,c as t,a2 as n}from"./chunks/framework.B-QBKwc1.js";const o=JSON.parse('{"title":"权限控制","description":"前端权限控制通过 v-perm / v-perms 指令实现按钮级权限控制。","frontmatter":{},"headers":[],"relativePath":"zh/frontend/permission.md","filePath":"zh/frontend/permission.md"}'),h={name:"zh/frontend/permission.md"};function l(k,s,e,p,r,d){return a(),t("div",null,[...s[0]||(s[0]=[n(`

9.7 权限控制 ​

概述

前端权限控制通过 v-perm / v-perms 指令实现按钮级权限控制。前端权限只是体验层(隐藏按钮),真正的安全防线是后端 #[Permission] 注解 + auth.jwt 中间件。

权限指令 ​

v-perm(单权限) ​

vue
<template>
  <!-- 只有拥有 sys:user:add 权限的用户才能看到此按钮 -->
  <el-button v-perm="['sys:user:add']" type="primary">新增</el-button>
</template>

v-perms(多权限,满足任一即可) ​

vue
<template>
  <!-- 拥有 sys:user:add 或 sys:user:update 任一权限即可 -->
  <el-button v-perms="['sys:user:add', 'sys:user:update']">操作</el-button>
</template>

指令实现 ​

typescript
// ui/src/directives/permission.ts

import { usePermission } from '@/hooks/web/usePermission';

export const perm: ObjectDirective = {
  mounted(el: HTMLButtonElement, binding) {
    const { hasSomePermission } = usePermission();
    if (!hasSomePermission(binding.value)) {
      el.parentNode.removeChild(el);  // 无权限则移除元素(非隐藏)
    }
  },
};

移除而非隐藏

无权限时元素直接从 DOM 移除(而非 display:none)——避免通过开发者工具看到"隐藏"的敏感操作按钮。

usePermission Hook ​

超级管理员

用户权限列表包含 *:*:* 时,表示超级管理员,拥有所有权限。

typescript
// ui/src/hooks/web/usePermission.ts

export function usePermission() {
  const userStore = useUserStore();

  /**
   * 检查是否拥有指定权限
   * 超级管理员(permissions 包含 '*:*:*')拥有所有权限
   */
  function hasSomePermission(permission: string | string[]): boolean {
    const perms = userStore.permissions;
    if (perms.includes('*:*:*')) return true;

    if (typeof permission === 'string') {
      return perms.includes(permission);
    }
    return permission.some((p) => perms.includes(p));
  }

  return { hasSomePermission, hasEveryPermission };
}

权限数据来源 ​

用户登录后,GET /api/index/getUser 接口返回权限列表(IndexService::getUser → JwtService::getUserPermissions,与后端鉴权同一缓存):

json
{
    "permissions": [
        "sys:user:page",
        "sys:user:add",
        "sys:user:update",
        "sys:user:delete",
        "sys:role:page"
    ]
}

超级管理员返回 ["*:*:*"],拥有所有权限。

权限码对应关系 ​

端机制示例
后端#[Permission('sys:user:add', '添加用户')] 注解 + 中间件反射鉴权403 拦截
前端v-perm="['sys:user:add']" 指令按钮移除
菜单laravel_menu.permission 字段(type=1 权限节点)角色树勾选

三处权限码必须完全一致(sys:{模块}:{操作})。

常见问题 ​

现象原因处理
按钮不显示但接口可调角色有权限码但 getUser 未返回重新登录刷新权限缓存
按钮显示但接口 403菜单 permission 与注解不一致逐字符比对权限码
超管按钮仍隐藏permissions 未含 *:*:*检查 getUser 返回(uid=1 应为通配)
修改角色权限后前端无变化前端权限缓存在 Store重新登录或刷新页面

详见 5.4 权限管理(RBAC)。

`,23)])])}const g=i(h,[["render",l]]);export{o as __pageData,g as default};