Skip to content

权限管理模块

概述

权限管理用于维护权限点(如 system.user.create),供路由鉴权与按钮鉴权统一使用。权限点是 RBAC 体系中最细粒度的控制单元,决定了用户可以执行哪些具体操作。

  • 路由:/organization/permission
  • 页面:src/views/system/permission/index.vue
  • 权限:system.permission.view
  • API:src/api/permission.ts

权限点设计规范

命名规范

采用 domain.resource.action 三段式命名:

typescript
// 格式:<模块>.<资源>.<操作>
const PERMISSION_EXAMPLES = {
  // 系统管理模块
  "system.user.view": "查看用户",
  "system.user.create": "新增用户",
  "system.user.edit": "编辑用户",
  "system.user.delete": "删除用户",

  "system.role.view": "查看角色",
  "system.role.create": "新增角色",
  "system.role.edit": "编辑角色",
  "system.role.delete": "删除角色",

  // 业务模块
  "order.list.view": "查看订单列表",
  "order.detail.view": "查看订单详情",
  "order.export": "导出订单",

  "report.dashboard.view": "查看仪表盘",
  "report.generate": "生成报表",
};

使用场景

typescript
// 1. 路由级权限
{
  path: '/system/user',
  meta: {
    requiredPermissions: ['system.user.view'],
  },
}

// 2. 按钮级权限 - 指令方式
<a-button v-permission="'system.user.create'">新增用户</a-button>

// 3. 按钮级权限 - 组件方式
<PermissionButton permission="system.user.delete" danger>删除</PermissionButton>

// 4. 编程式权限检查
const { can } = usePermission()
if (can('system.user.edit')) {
  // 有编辑权限
}

核心能力

1. 权限点树形维护

vue
<template>
  <a-table
    :columns="columns"
    :data-source="permissionTree"
    :pagination="false"
    :default-expand-all-rows="true"
    children-column-name="children"
  >
    <template #bodyCell="{ column, record }">
      <template v-if="column.dataIndex === 'code'">
        <a-tag>{{ record.code }}</a-tag>
      </template>
      <template v-if="column.dataIndex === 'type'">
        <a-tag :color="record.type === 'menu' ? 'blue' : 'green'">
          {{ record.type === "menu" ? "菜单" : "按钮" }}
        </a-tag>
      </template>
    </template>
  </a-table>
</template>

2. 权限点新增/编辑/删除

typescript
const formItems: ProFormItem[] = [
  { type: "input", name: "name", label: "权限名称", required: true },
  { type: "input", name: "code", label: "权限标识", required: true },
  {
    type: "select",
    name: "type",
    label: "权限类型",
    options: [
      { label: "菜单", value: "menu" },
      { label: "按钮", value: "button" },
    ],
    defaultValue: "button",
  },
  {
    type: "tree-select",
    name: "parentId",
    label: "上级权限",
    treeData: permissionTree,
  },
  { type: "input-number", name: "sort", label: "排序", defaultValue: 0 },
];

3. 角色与权限点联动

typescript
// 获取角色的权限树
const getRolePermissionTree = async (roleId: string) => {
  const allPermissions = await getAllPermissions();
  const rolePermissions = await getRolePermissions(roleId);

  // 标记已选中的权限
  const checkedIds = new Set(rolePermissions.map((p) => p.id));

  return {
    tree: buildPermissionTree(allPermissions),
    checkedKeys: Array.from(checkedIds),
  };
};

数据结构

typescript
interface PermissionItem {
  id: string;
  name: string; // 权限名称
  code: string; // 权限标识
  type: "menu" | "button"; // 权限类型
  parentId?: string; // 父级 ID
  path?: string; // 菜单路径(type=menu)
  icon?: string; // 图标
  sort: number; // 排序
  status: "active" | "inactive";
  children?: PermissionItem[];
}

最佳实践

1. 先定义权限字典

typescript
// constants/permissions.ts
export const PERMISSIONS = {
  // 用户管理
  USER_VIEW: 'system.user.view',
  USER_CREATE: 'system.user.create',
  USER_EDIT: 'system.user.edit',
  USER_DELETE: 'system.user.delete',

  // 角色管理
  ROLE_VIEW: 'system.role.view',
  ROLE_CREATE: 'system.role.create',
  ROLE_EDIT: 'system.role.edit',
  ROLE_DELETE: 'system.role.delete',
} as const

// 使用
import { PERMISSIONS } from '@/constants/permissions'

<a-button v-permission="PERMISSIONS.USER_CREATE">新增</a-button>

2. 权限命名保持稳定

typescript
// ✅ 好:权限命名稳定
'system.user.create'

// ❌ 避免:频繁重命名
'system.user.add''system.user.create''system.user.new'

3. 前端权限仅用于体验优化

typescript
// 前端隐藏无权限按钮(体验优化)
<a-button v-permission="'system.user.delete'" danger>删除</a-button>

// 后端必须做真正的权限校验
@DeleteMapping("/users/{id}")
@PreAuthorize("hasPermission('system.user.delete')")
public void deleteUser(@PathVariable String id) {
  // ...
}

4. 权限缓存与更新

typescript
// stores/permission.ts
export const usePermissionStore = defineStore("permission", () => {
  const permissions = ref<string[]>([]);

  // 获取权限列表
  const fetchPermissions = async () => {
    const res = await getMyPermissions();
    permissions.value = res.map((p) => p.code);
  };

  // 检查权限
  const hasPermission = (code: string) => {
    return permissions.value.includes(code);
  };

  return { permissions, fetchPermissions, hasPermission };
});

权限继承设计

typescript
// 权限继承关系
interface PermissionTreeNode extends PermissionItem {
  inheritedFrom?: string[]; // 从哪些角色继承而来
}

// 计算用户最终权限
const calculateUserPermissions = (user: User) => {
  const permissionSet = new Set<string>();

  // 遍历用户所有角色
  for (const role of user.roles) {
    for (const perm of role.permissions) {
      permissionSet.add(perm.code);
    }
  }

  return Array.from(permissionSet);
};

相关文档

基于 MIT 许可发布