如何实现前端页面权限和按钮权限

页面权限是后台系统中非常常见的需求,在前端实现页面权限和按钮权限是为了确保用户只能访问其有权访问的页面,并执行其有权执行的操作。本文介绍前端实现页面权限和按钮权限控制的流程和逻辑。

以下的代码以Ant Design Pro 项目为例,其中封装了一些常见的权限处理方式,如路由菜单权限,按钮权限,Access 组件,useAccess 函数等。但是实现原理是类似的,其他框架也可参考该流程实现。

1. 获取用户当前权限并且存在全局状态中

首先需要从后端接口中获取到当前用户拥有的所有权限列表,并且存储在全局状态中(这个场景中使用全局状态库是一个很合适的方式)。

tsx 复制代码
export async function getInitialState() {
  // ...
  const userPermissions = await fetchUserPermissions();
  return {
    // ....
    userPermissions,
  };
}

2. 定义页面权限标记

需要将每个需要权限控制的页面和操作按钮提前定义好权限标记(某个 key),后续中使用用户拥有的权限和这个权限标记对比当前用户是否拥有权限。

这里直接写成一份常量维护,方便在不同组件中使用和维护。

typescript 复制代码
const PERMISSIONS = {
  PAGEA: {
    READ: "PAGEA_READ", // 页面访问权限标记
    ADD: "PAGEA_ADD" // 页面中操作按钮权限标记
    // ... 其他页面中操作按钮
  }
  // ... 其他页面权限标记
}

3. 路由和菜单的权限控制

将之前定义好的权限标记路由和对应的页面上。这里使用里自定义的字段 meta 中的 permission,后续可以直接从当前路由信息中取出这个页面的权限。

typescript 复制代码
export const routes = [
  {
    path: '/pageA',
    component: 'PageA',
    access: 'canAccessRoute', // 会调用 src/access.ts 中返回的 canAccessRoute 进行鉴权
    meta: {
      permission: PERMISSIONS.PAGEA.READ, // 页面访问权限标记
    },
  },
  {
    path: '/pageB',
    component: 'PageB',
    access: 'canAccessRoute', // 会调用 src/access.ts 中返回的 canAccessRoute 进行鉴权
    meta: {
      permission: PERMISSIONS.PAGEB.READ, // 页面访问权限标记
    },
  },
];

编写判断用户是否拥有页面权限判断逻辑,其逻辑十分简单,即判断当前路由权限标记是否在用户拥有的权限中。

typescript 复制代码
export default function access(initialState) {
  const { userPermissions } = initialState ?? {};

  function canAccessRoute(route: IRoute) {
    // 页面对应的权限标记,需要在当前用户拥有的权限中
    if (route.meta?.permission) {
      return userPermissions.includes(route.meta.permission);
    }
    // 无页面权限标记说明改页面不需要权限也能访问
    return true;
  }

  return {
    canAccessRoute,
  };
}

4. 按钮权限控制

按钮权限的控制也可以依照之前页面权限的设计,先定义好操作按钮权限标记,然后判断用户是否拥有该权限。

typescript 复制代码
export default function access(initialState) {
  // ...

  function canAccessAction(permissions: string[]) {
    // 按钮对应的权限标记,需要在当前用户拥有的权限中
    return permissions.every((permission) => userPermissions.includes(permission));
  }

  return {
    // ...
    canAccessAction
  };
}

为操作按钮添加权限控制时,可以使用封装的通用的权限组件,将该组件包裹操作按钮,只需要传入是否拥有权限即可。

注意:除了前端对操作按钮添加权限控制,一般后端也需要在对应接口中根据用户的角色和权限进行校验,返回允许或拒绝的结果。

tsx 复制代码
function PageA() {
  const { canAccessAction } = useAccess();

  return (
   <Access accessible={canAccessAction([PERMISSIONS.PAGEA.ADD])}>
      <Button>新增</Button>
    </Access>
  )
}

封装一个通用的权限组件在 React 中是十分简单的,例如 Umi 中的 Access 组件

tsx 复制代码
export interface AccessProps {
  accessible: boolean;
  fallback?: React.ReactNode;
}
export const Access: React.FC<PropsWithChildren<AccessProps>> = (props) => {
  if (process.env.NODE_ENV === 'development' && typeof props.accessible !== 'boolean') {
    throw new Error('[access] the \`accessible\` property on <Access /> should be a boolean');
  }

  return <>{ props.accessible ? props.children : props.fallback }</>;
};

参考链接

相关推荐
万少4 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站6 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名8 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫9 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊9 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter9 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折9 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_9 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
不会敲代码19 小时前
前端组件化样式隔离实战:React CSS Modules、styled-components 与 Vue scoped 对比
css·vue.js·react.js
Angelial9 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js