Skip to content

权限控制说明

本系统采用基于角色的访问控制(RBAC)模型,结合 PocketBase 后端的集合管理,实现了多层次的权限保护。

角色定义

系统目前定义了两种核心角色:

  1. 超级管理员 (superuser)

    • 后端来源:PocketBase 的 _superusers 集合。
    • 权限范围:拥有系统最高权限,可以管理其他用户、修改核心设置、访问所有模块。
    • 识别标志:在 UI 顶部显示 "Admin" 标签。
  2. 普通管理员 (user)

    • 后端来源:PocketBase 的 users 集合。
    • 权限范围:通常只能访问业务模块(如数据中心、订单管理),无权访问“用户管理”等系统级管理页面。
    • 识别标志:显示为“普通用户”。

认证流程

用户在登录页面通过“超级管理员登录”勾选项决定认证路径:

  • 勾选:调用 pb.collection('_superusers').authWithPassword(...)
  • 不勾选:调用 pb.collection('users').authWithPassword(...)

认证成功后,状态将保存在 AuthProvider 的 React Context 中。

开发实现

1. 状态共享 (useAuth)

通过 useAuth 钩子,可以在任何组件中获取当前用户的角色状态:

typescript
const { user, isSuperAdmin, isValid } = useAuth();

2. 路由保护

src/components/protected-route.tsx 中定义了三种保护组件:

  • <ProtectedRoute />:确保用户已登录(无论何种角色)。未登录则重定向至 /login
  • <AdminOnlyRoute />:确保用户不仅已登录,且必须是超级管理员。否则重定向至首页。
  • <UserOnlyRoute />:确保用户不仅已登录,且必须是普通用户。否则重定向至超级管理员后台。

模块化路由配置(推荐方式)

为了保持代码的模块化,建议直接在模块的 routes.tsx 中配置权限。

示例:src/pages/portal/routes.tsx

tsx
export const PortalRoutes = (
    <Route path="portal">
        {/* 公开路由 */}
        <Route path="landing" element={<LandingPage />} />
        
        {/* 需要登录访问的私有路由 */}
        <Route element={<ProtectedRoute />}>
            <Route path="blog-detail" element={<BlogDetail />} />
        </Route>
    </Route>
);

示例:src/App.tsx 中的注册

tsx
<Routes>
  <Route path="/login" element={<LoginPage />} />
  
  {/* 直接挂载模块路由,权限由模块内部定义 */}
  {PortalRoutes}
  
  <Route element={<ProtectedRoute />}>
    <Route path="/" element={<MainLayout />}>
      {TaskRoutes}
      {/* 其他需要通用布局的受保护路由 */}
    </Route>
  </Route>
</Routes>

3. UI 动态过滤

侧边栏会根据角色自动过滤菜单项。在 Sidebar.tsx 中,每个菜单项可以配置 adminOnly: true

typescript
{
  title: '用户管理',
  path: '/users',
  icon: UserIcon,
  adminOnly: true, // 设置后,普通用户在侧边栏看不到该项
}

数据安全说明

除了前端的 UI 和路由保护外,最终的安全保障由 PocketBase 的 API Rules (ACL) 实现:

  • users 集合的记录应设置为仅超级管理员可管理。
  • 各业务集合的增删改查规则应根据业务需求配置 @request.auth.id != "" 或更细粒度的规则。