Appearance
AccessControl
简介
@ifanrx/dashboard
配备了一套基于 RBAC 的权限控制方案,在项目内可按需使用
通过 @ifanrx/scaffolder
创建的 dashboard 项目已经内置了权限控制,无需额外配置
搭建权限系统
对于非脚手架生成的项目,可根据以下步骤接入权限系统
创建数据表
以下数据表都只提供 JSON Schema,可复制到知晓云或者表设计工具内快速建表
admin
Click me to view the code
json
{
"name": "admin",
"description": "管理员账号",
"row_read_perm": ["user:{created_by}"],
"row_write_perm": [],
"write_perm": [],
"schema": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "status",
"type": "string",
"description": "管理员状态",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": [
{
"type": "choices",
"value": ["active", "inactive"],
"remark": ["启用", "禁用(软删)"]
}
]
}
},
{
"name": "name",
"type": "string",
"description": " 管理员名称",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": false,
"rules": []
}
},
{
"name": "email",
"type": "string",
"description": "管理员邮箱",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "roles",
"type": "array",
"description": " 当前管理员分配的角色",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"default": [],
"constraints": {
"required": true,
"rules": []
},
"items": {
"type": "string"
}
},
{
"name": "root",
"type": "boolean",
"description": "是否为超级管理员",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": false,
"rules": []
},
"default": false
},
{
"name": "updated_by",
"type": "object",
"description": "操作者信息快照",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
},
"indexes": [
{
"fields": ["email"]
}
],
"design_tool": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "status",
"type": "string",
"description": "管理员状态",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": [
{
"type": "choices",
"value": ["active", "inactive"],
"remark": ["启用", "禁用(软删)"]
}
]
}
},
{
"name": "name",
"type": "string",
"description": " 管理员名称",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": false,
"rules": []
}
},
{
"name": "email",
"type": "string",
"description": "管理员邮箱",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "roles",
"type": "array",
"description": " 当前管理员分配的角色",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"default": [],
"constraints": {
"required": true,
"rules": []
},
"items": {
"type": "string"
}
},
{
"name": "root",
"type": "boolean",
"description": "是否为超级管理员",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": false,
"rules": []
},
"default": false
},
{
"name": "updated_by",
"type": "object",
"description": "操作者信息快照",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
}
}
role
Click me to view the code
json
{
"name": "role",
"description": "角色,每条记录即为一种角色",
"row_read_perm": ["user:*"],
"row_write_perm": [],
"write_perm": ["user:*"],
"schema": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "name",
"type": "string",
"description": "角色名称",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "privileges",
"type": "array",
"description": "角色拥有权限 id",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"default": [],
"constraints": {
"required": true,
"rules": []
},
"items": {
"type": "string"
}
},
{
"name": "updated_by",
"type": "object",
"description": "操作者信息",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
},
"design_tool": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "name",
"type": "string",
"description": "角色名称",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "privileges",
"type": "array",
"description": "角色拥有权限 id",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"default": [],
"constraints": {
"required": true,
"rules": []
},
"items": {
"type": "string"
}
},
{
"name": "updated_by",
"type": "object",
"description": "操作者信息",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
}
}
privilege
Click me to view the code
json
{
"name": "privilege",
"description": "权限",
"row_read_perm": ["user:*"],
"row_write_perm": [],
"write_perm": ["user:*"],
"schema": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "category",
"type": "string",
"description": "权限所属类目",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "value",
"type": "string",
"description": "权限内容,由 action-object 组成",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "display",
"type": "string",
"description": "用户实际看到的权限描述,通常由权限同步脚本生成,value.replace(/-/g, '')",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "uuid",
"type": "string",
"description": "权限 id,在 definePrivileges 时填入",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
},
"design_tool": {
"fields": [
{
"name": "id",
"type": "id",
"description": "id"
},
{
"name": "category",
"type": "string",
"description": "权限所属类目",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "value",
"type": "string",
"description": "权限内容,由 action-object 组成",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "display",
"type": "string",
"description": "用户实际看到的权限描述,通常由权限同步脚本生成,value.replace(/-/g, '')",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "uuid",
"type": "string",
"description": "权限 id,在 definePrivileges 时填入",
"acl": {
"clientReadOnly": false,
"clientVisible": true,
"creatorVisible": false
},
"constraints": {
"required": true,
"rules": []
}
},
{
"name": "created_by",
"type": "integer",
"description": "created_by"
},
{
"name": "created_at",
"type": "integer",
"description": "created_at"
},
{
"name": "updated_at",
"type": "integer",
"description": "updated_at"
}
]
}
}
在项目内接入模块
定义路由
在项目根路径下创建 route.js
文件
Details
jsx
import {
defineRouteList,
DEFAULT_PRIVILEGE,
definePrivilege,
} from '@ifanrx/dashboard'
// 获取当前 pages 内容,需在 defineRouteList 传入
const pages = import.meta.glob(['@/pages/*.jsx', '@/pages/*/index.jsx'])
export const ROUTE = {
WELCOME: '/welcome',
ADMIN_LIST: '/admin-list',
ADMIN_ADD: '/admin-edit',
ADMIN_EDIT: '/admin-edit/:id',
ADMIN_ROLE_LIST: '/admin-role-list',
ADMIN_ROLE_ADD: '/admin-role-edit',
ADMIN_ROLE_EDIT: '/admin-role-edit/:id',
}
/** @type {import('@ifanrx/dashboard').Route[]} */
const routeOptions = [
{
path: ROUTE.WELCOME,
menuTitle: '欢迎',
// 若当前页面所有人可访问,可使用 DEFAULT_PRIVILEGE 填充给 privileges
privileges: [DEFAULT_PRIVILEGE],
// icon 需传入构造函数,不支持使用组件
icon: SmileFilled,
},
{
menuTitle: '管理员',
icon: TeamOutlined,
children: [
{
path: ROUTE.ADMIN_LIST,
menuTitle: '管理员列表',
privileges: [
// 可通过 definePrivilege 定义新的权限,会在下文 definePrivilege 章节中说明
definePrivilege(
'管理员',
'查看-管理员列表',
'c6d42cb1-b26d-4f49-a535-3de416f3f5a6'
),
// privileges 可配置多个权限,当前登录用户拥有其中一个权限即可访问该路由
definePrivilege(
'管理员',
'编辑-管理员信息',
'80659315-600e-4c4c-90f5-2bab8a9125c2'
),
],
children: [
{
path: ROUTE.ADMIN_ADD,
name: '新增管理员',
privileges: [
// 使用重复权限时,无需重复定义,可使用 getPrivilege 来获取权限
getPrivilege('管理员', '编辑-管理员信息'),
],
},
{
path: ROUTE.ADMIN_EDIT,
name: '编辑管理员',
privileges: [getPrivilege('管理员', '编辑-管理员信息')],
},
],
},
{
path: ROUTE.ADMIN_ROLE_LIST,
menuTitle: '管理员角色',
privileges: [
definePrivilege(
'管理员',
'查看-管理员角色',
'31169c04-b72b-458e-91b8-52e5506e9bbe'
),
],
children: [
{
path: ROUTE.ADMIN_ROLE_ADD,
name: '新增管理员角色',
privileges: [
definePrivilege(
'管理员',
'新增-管理员角色',
'b0c6a603-c85c-4f22-aa43-9d9b075bebb7'
),
],
},
{
path: ROUTE.ADMIN_ROLE_EDIT,
name: '编辑管理员角色',
privileges: [
definePrivilege(
'管理员',
'编辑-管理员角色',
'637338fc-d6f9-4e20-b3b4-88912f481340'
),
],
},
],
},
],
},
]
export const routeList = defineRouteList(routeOptions, pages)
Route 定义
属性 | 类型 | 可选 | 说明 |
---|---|---|---|
privileges | Privilege[] | 是 | 路由的权限配置。所有路由都必须配置此属性。若需要表示无权限也可访问,需要将 DEFAULT_PRIVILEGE 配置进 privileges 。上级路由会继承所有下级路由的 privileges 。 |
menuTitle | string | 是 | 菜单栏显示的标题。配置此字段表示该路由需要显示在菜单栏中。menuTitle 和 name 必须至少配置一个,用于 RouterBreadcrumb 内部依赖。 |
name | string | 是 | 路由名称。若 menuTitle 为空,则需要配置 name 。menuTitle 和 name 必须至少配置一个,用于 RouterBreadcrumb 内部依赖。 |
path | string | 是 | 路由路径。 |
icon | import('react').ReactNode | 是 | 配置菜单栏内的图标,需要使用图标的构造函数。 |
children | Route[] | 是 | 下级路由配置。 |
render | Function | 是 | 自定义菜单栏内路由节点的渲染方法。 |
lazy | any | 是 | 为空时会根据 path 自动在 src/pages 目录内找到同名文件。亦可指定文件,使用 lazyLoader 方法引入。 |
privilegeController | PrivilegeController | 是 | 若 privileges 不满足于判断是否显示该路由,可通过该函数进行扩展。返回 true 表示路由可见,仅支持同步函数。 |
key | string | 是 | 由 genRoute 自动生成。 |
parentKey | string | 是 | 由 genRoute 自动生成。 |
hasPrivilege | boolean | 是 | 由 genRoute 自动生成。根据 privileges 和 privilegeController 控制。 |
menuItemRender | MenuItemRender | 是 | 自定义菜单项渲染方法。 |
接入 AccessRouterProvider
在项目 App.jsx 文件内引入以下模块以及代码
Details
jsx
import {
acl as aclState,
initAcl,
AccessRouterProvider,
AccessRouterLayout,
} from '@ifanrx/dashboard'
export default function App() {
// your code...
const acl = useSnapshot(aclState)
useMount(() => {
// routeList 指通过 defineRouteList 生成的产物
initAcl(routeList)
})
return (
// your code...
{!isEmpty(acl.accessRouteList) ? (
<AccessRouterProvider accessRouteList={acl.accessRouteList}>
<AccessRouterLayout
accessRouteList={acl.accessRouteList}
logo="https://cloud-minapp-39778.cloud.ifanrusercontent.com/1n8GDl96Mg4usjDQ.png"
title={PROJECT_NAME}
userprofile={acl.userprofile}
/>
</AccessRouterProvider>
) : null}
// your code...
)
}
禁用权限系统
通过 @ifanrx/scaffolder
创建的 dashboard 项目已经内置了权限控制,如果需要禁用权限,可在 App.jsx
内找到 initAcl
函数的调用,传入 withoutAccess: true 即可
jsx
export default function App() {
// your code...
useMount(() => {
initAcl(routeList, {withoutAccess: true})
})
// your code...
}
禁用权限系统后,项目不再需要创建 admin/privilege/role 表,所有用户均可访问所有页面
用户状态管理
acl
基于 valtio 代理的用户状态,包含用户信息、用户权限集合、用户可访问的路由列表
js
export const acl = proxy({
/**
* 当前登录用户的信息
* @type {Userprofile|null}
*/
userprofile: null,
/**
* 当前登录用户可访问的路由信息
* @type {import('./define-route-list').Route[]}
*/
accessRouteList: [],
/**
* 当前登录用户的权限集
* @type {import('./define-route-list').Privilege[]}
*/
privileges: [DEFAULT_PRIVILEGE],
/**
* 当前登录用户在 admin 表的 record
* @type {Admin}
*/
admin: null,
})
使用前需使用 initAcl 对 acl 进行初始化
initAcl
对 acl 进行初始化,包括用户信息获取、权限获取、路由权限校验
js
/**
* @typedef InitAclOptions
* @prop {boolean} [withoutAccess = false] 禁用权限路由,当 withoutAccess 为 true 时,不对路由权限进行校验,defineRouteList 也无需传 privileges 配置
*/
/**
* @callback InitAcl
* @param {import('./define-route-list').Route[]} routeList
* @param {InitAclOptions} options
* @return {Promise<Acl>}
*/
其中 routeList 是 defineRouteList 定义的路由列表
options.withoutAccess 为 true 时,不对路由权限进行校验,defineRouteList 也无需传 privileges 配置
example
jsx
const routeList = defineRouteList([...])
export default function App() {
useMount(() => {
initAcl(routeList, {withoutAccess: false})
})
}
privilege
definePrivilege
definePrivilege 用于创建新的权限
ts
/**
* @template {string} Category
* @template {string} Value
* @template {string} Uuid
* @param {Category} category
* @param {Value} value action-objects
* @param {Uuid} uuid
* @example
* definePrivilege('管理员', '查看-管理员列表', '9af166f0-3322-4804-93ff-24e5bdabb8e9')
* @return {{category: Category, value: Value, Uuid: string}}
*/
category 为分类,一般为顶级菜单名称,如:管理员、活动管理
value 的组成一般情况下由 [action-object] 组成,如:查看-活动列表、编辑-活动、新增-活动、删除-活动。@ifanrx/dashboard 内的 definePrivilege 必须使用 [action-object] 来定义 value,如项目内有特殊需求,可在参数不变的前提下自行定义 definePrivilege 方法,修改 value 的校验条件
uuid 为唯一索引,每个 privilege 必须有自己的 uuid 且不可重复
TIP
可使用 VSCode UUID Generator 插件来生成 uuid,或者其他任何方法都可以,但是需要保证 uuid 的唯一性
example
js
export const routeList = defineRouteList([
{
path: ROUTE.ADMIN_LIST,
menuTitle: '管理员列表',
privileges: [
definePrivilege(
'管理员',
'查看-管理员列表',
'bc3505f9-ef5d-4647-987b-b07ead208205'
),
],
icon: SmileFilled,
},
])
getPrivilege
getPrivilege 用于获取已存在的权限,如果在这之前已经通过 definePrivilege 一个权限了,之后再次使用这个权限时,应使用 getPrivilege,此时不再需要使用 uuid,会根据 category 以及 value 来进行索引
ts
declare function getPrivilege<Category extends string, Value extends string>(
category: Category,
value: Value
): {category: Category; value: Value}
example
js
export const routeList = defineRouteList([
{
path: ROUTE.ADMIN_LIST,
menuTitle: '管理员列表',
privileges: [
definePrivilege(
'管理员',
'查看-管理员列表',
'bc3505f9-ef5d-4647-987b-b07ead208205'
),
],
icon: SmileFilled,
},
{
path: ROUTE.CHILD_TRADE_UNION_ADMIN_LIST,
menuTitle: '下级工会管理员列表',
privileges: [getPrivilege('管理员', '查看-管理员列表')],
icon: SmileFilled,
},
])
hasPrivilege
校验用户是否拥有某个权限,同时支持接受单个权限或者一个权限集合作为参数
example
jsx
// hasPrivilege({category: '管理员', value: '查看-管理员列表'})
// hasPrivilege([{category: '管理员', value: '查看-管理员列表'}, {category: '管理员', value: '修改-管理员列表'}])
function updateAdmin() {
if (!hasPrivilege({category: '管理员', value: '修改-管理员'})) {
message.error('没有权限修改管理员信息')
return
}
// ...
}
function AdminList() {
if (
!hasPrivilege([
{category: '管理员', value: '查看-管理员列表'},
{category: '管理员', value: '修改-管理员列表'},
])
) {
return <WithoutAccess>没有权限</WithoutAccess>
}
return <Table />
}
push-privilege
push-privilege 是一个脚本,可以将项目内通过 definePrivilege 定义的 privilege 收集并上传到 privilege 表内,执行脚本前需要确保已经 创建数据表 以及已经通过 mincloud login
登录知晓云
使用 definePrivilege 定义新权限后,一定要执行该脚本将最新的权限集合同步到数据表,否则无法给管理员设置对应权限
用法如下:
bash
push-privilege // 同步 privilege 到生产环境数据表
push-privilege --envId YOUR_ENV_ID // 同步 privilege 到知晓云测试环境数据表,需要把 YOUR_ENV_ID 替换为实际的 env id
push-privilege --qa // 同步 privilege 到知晓云 QA 应用,需确保已经通过 mincloud login --qa 登录知晓云
通过 @ifanrx/scaffolder 创建的项目已经在 script 内置了这几个命令,可以直接使用
json
{
"script": {
"push-privilege": "push-privilege",
"push-privilege:dev": "push-privilege --envId YOUR_ENV_ID",
"push-privilege:qa": "push-privilege --qa"
}
}
权限路由
defineRouteList
权限系统内使用的路由列表必须是通过 defineRouteList 定义出来的,作用是根据 path 给每个路由挂载页面组件,函数定义如下:
ts
/**
* @callback DefineRouteList
* @param {Route[]} routeOptions
* @param {object} pages
* @return {Route[]}
*/
routeOptions 定义查看 Route 定义
pages 为项目内 pages 目录下的文件模块,pages = import.meta.glob(['@/pages/*.jsx', '@/pages/*\/index.jsx])
,是固定搭配,如果项目目录结构不同,自行修改目录名称即可
example
lazyLoader
在 defineRouteList 内配置路由 path 时,会在 pages 内匹配对应的页面文件,如:path 为 /admin-list 时,会尝试匹配 /pages/admin-list.jsx 或者 /pages/admin-list/index.jsx,都匹配不到时报 Page Not Found
当页面文件路径与上述规则不匹配时,可在定义路由时手动传入 lazy 参数来匹配页面文件,如:
js
const pages = import.meta.glob(['@/pages/*.jsx', '@/pages/*/index.jsx'])
const ROUTE = {
PRIZE_LOG: '/prize-log/:type/:id',
// 根据奖品 id 查询奖品发放记录
PRIZE_LOG_WITH_PRIZE_ID: '/prize-log/prize/:id',
// 根据活动 id 查询奖品发放记录
PRIZE_LOG_WITH_ACTIVITY_ID: '/prize-log/activity/:id',
}
export const routeList = defineRouteList([
{
path: ROUTE.PRIZE_LOG_WITH_PRIZE_ID,
name: '发放记录',
privileges: [
definePrivilege(
'活动管理',
'查看-发放记录',
'bc3505f9-ef5d-4647-987b-b07ead208205'
),
],
lazy: lazyLoader(ROUTE.PRIZE_LOG, pages),
},
{
path: ROUTE.PRIZE_LOG_WITH_ACTIVITY_ID,
menuTitle: '发放记录',
privileges: [getPrivilege('活动管理', '查看-发放记录')],
lazy: lazyLoader(ROUTE.PRIZE_LOG, pages),
},
])
DEFAULT_PRIVILEGE
用于配置不需要权限的路由
example
js
export const routeList = defineRouteList([
{
path: ROUTE.WELCOME,
menuTitle: '欢迎',
// 若当前页面所有人可访问,可使用 DEFAULT_PRIVILEGE 填充给 privileges
privileges: [DEFAULT_PRIVILEGE],
},
])
权限控制组件
Privilege
▸ Privilege(options
): ReactElement
<any
, string
| JSXElementConstructor
<any
>>
用于包裹需要校验访问权限的组件
默认情况下,当用户拥有权限时渲染 children,无权限时不进行任何渲染,可通过 fallback 自定义无权限时的渲染组件
当 children 为 function 时,可接收 hasPrivilege 参数,需开发者根据 hasPrivilege 值自行返回组件
参数
Name | Type | Default value | Description |
---|---|---|---|
options | Object | undefined | |
options.children | undefined | Function | undefined | |
options.fallback | undefined | null | ReactElement <any , string | JSXElementConstructor <any >> | null | 无权限时渲染组件,默认不渲染,当 children 为 Function 时,fallback 优先级高于 children |
options.privileges | Privilege [] | [] | 访问该模块所需权限集 |
返回值
ReactElement
<any
, string
| JSXElementConstructor
<any
>>
示例
- 有权限时显示组件,无权限时隐藏组件
jsx
<Privilege privileges={[getPrivilege('管理员', '查看-管理员列表')]}>
<AdminList />
</Privilege>
- 有权限时显示组件,无权限时显示 fallback 内容
jsx
<Privilege
fallback={<WithoutAccess />}
privileges={[getPrivilege('管理员', '查看-管理员列表')]}
>
<AdminList />
</Privilege>
- 自定义
jsx
<Privilege privileges={privileges}>
{({hasPrivilege}) => (
<Button
{...buttonProps}
onClick={() => (hasPrivilege ? success() : fail())}
>
权限按钮
</Button>
)}
</Privilege>
源码
PrivilegeButton
▸ PrivilegeButton(options
): ReactElement
<any
, string
| JSXElementConstructor
<any
>>
根据用户是否有权限控制按钮组件点击事件
默认情况下,当用户拥有权限时会正常出发 onClick,无权限时会弹窗提醒用户,可通过 deniedMsg 修改弹窗内容或者通过 onDenied 自定义无权限时回调
本组件继承 antd Button 所有 props
参数
Name | Type |
---|---|
options | ButtonProps & Options |
返回值
ReactElement
<any
, string
| JSXElementConstructor
<any
>>
示例
- 基础用法
jsx
<PrivilegeButton
privileges={[getPrivilege('管理员', '新增-管理员')]}
size="large"
type="primary"
onClick={() => navigate(ROUTE.ADMIN_ADD)}
>
新增
</PrivilegeButton>
- 自定义 onDenied
jsx
<PrivilegeButton
privileges={[getPrivilege('管理员', '新增-管理员')]}
size="large"
type="primary"
onClick={() => navigate(ROUTE.ADMIN_ADD)}
onDenied={() =>
modal.confirm({
title: '暂无权限',
content: '点击「确定」像管理员申请权限',
onOk: () => navigate(ROUTE.XXXX),
})
}
>
新增
</PrivilegeButton>