项目背景

在企业级管理后台系统中,用户权限管理是必不可少的模块。
典型需求包括:

  • 不同角色访问不同页面和功能
  • 动态渲染菜单与按钮
  • 后端接口权限控制配合前端渲染
  • 可扩展的权限体系,便于后期增加新角色或功能

我所在的项目中,涉及 多层级权限(管理员、部门主管、普通员工)以及 功能粒度控制(按钮、操作权限)。


权限体系设计

角色与权限分离

  • 角色(Role):用户所属身份,如 AdminManagerStaff
  • 权限(Permission):具体操作,如 canEditUsercanViewReport

后端返回:

{
  "roles": ["Manager"],
  "permissions": ["viewDashboard", "editProject", "viewReports"]
}

前端权限控制点

  • 页面访问路由控制
  • 菜单动态渲染
  • 按钮/操作隐藏或禁用
  • API 请求前判断权限(避免错误调用)

实战实现

React + Context 管理权限

import React, { createContext, useContext } from 'react';

interface AuthContextType {
  roles: string[];
  permissions: string[];
}

const AuthContext = createContext<AuthContextType>({
  roles: [],
  permissions: [],
});

export const useAuth = () => useContext(AuthContext);

export const AuthProvider = ({
  children,
  roles,
  permissions,
}: AuthContextType & { children: React.ReactNode }) => (
  <AuthContext.Provider value={{ roles, permissions }}>
    {children}
  </AuthContext.Provider>
);

路由守卫

import { useAuth } from './AuthContext';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({
  children,
  requiredPermissions,
}: {
  children: React.ReactNode;
  requiredPermissions: string[];
}) {
  const { permissions } = useAuth();
  const hasAccess = requiredPermissions.every((p) => permissions.includes(p));

  return hasAccess ? <>{children}</> : <Navigate to="/403" replace />;
}

菜单动态渲染

import { useAuth } from './AuthContext';

const menuItems = [
  { title: 'Dashboard', key: 'dashboard', permission: 'viewDashboard' },
  { title: '项目管理', key: 'project', permission: 'editProject' },
  { title: '报表', key: 'reports', permission: 'viewReports' },
];

function Sidebar() {
  const { permissions } = useAuth();
  return (
    <ul>
      {menuItems
        .filter((item) => permissions.includes(item.permission))
        .map((item) => (
          <li key={item.key}>{item.title}</li>
        ))}
    </ul>
  );
}

按钮/操作级权限

function EditButton() {
  const { permissions } = useAuth();
  if (!permissions.includes('editProject')) return null;
  return <button className="btn-primary">编辑项目</button>;
}

优化技巧

  1. 缓存权限信息

    使用 localStorage 或全局状态缓存,避免每次渲染重复请求

  2. 组合权限函数

    封装 hasPermission(permission) 函数,统一判断

  3. 类型安全

    在 TypeScript 中使用字符串字面量类型或 enum 定义权限,避免拼写错误

    type Permission = 'viewDashboard' | 'editProject' | 'viewReports';
    
    function hasPermission(
      userPermissions: Permission[],
      permission: Permission,
    ) {
      return userPermissions.includes(permission);
    }
    
  4. 与后端权限对齐

    前端只做 UI 隐藏,实际敏感操作仍需后端校验

总结

前端权限系统是企业级应用的关键模块:

  • 灵活设计角色和权限模型
  • SPA 内通过 Context + 路由守卫 + 条件渲染实现动态控制
  • 使用 TypeScript 可提高安全性
  • 缓存与组合权限判断可提升性能和可维护性

实践中,权限系统越早设计,越容易扩展,同时减少后期迭代的冲突和重复开发。