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

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

以下的代码以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 }</>;
};

参考链接

相关推荐
golitter.7 分钟前
Ajax和axios简单用法
前端·ajax·okhttp
雷特IT26 分钟前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript
长路 ㅤ   1 小时前
vite学习教程02、vite+vue2配置环境变量
前端·vite·环境变量·跨环境配置
亚里士多没有德7751 小时前
强制删除了windows自带的edge浏览器,重装不了怎么办【已解决】
前端·edge
micro2010141 小时前
Microsoft Edge 离线安装包制作或获取方法和下载地址分享
前端·edge
.生产的驴1 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw1 小时前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
九圣残炎1 小时前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis
柏箱2 小时前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css
TU^2 小时前
C语言习题~day16
c语言·前端·算法