权限控制说明
本系统采用基于角色的访问控制(RBAC)模型,结合 PocketBase 后端的集合管理,实现了多层次的权限保护。
角色定义
系统目前定义了两种核心角色:
超级管理员 (superuser):
- 后端来源:PocketBase 的
_superusers集合。 - 权限范围:拥有系统最高权限,可以管理其他用户、修改核心设置、访问所有模块。
- 识别标志:在 UI 顶部显示 "Admin" 标签。
- 后端来源:PocketBase 的
普通管理员 (user):
- 后端来源:PocketBase 的
users集合。 - 权限范围:通常只能访问业务模块(如数据中心、订单管理),无权访问“用户管理”等系统级管理页面。
- 识别标志:显示为“普通用户”。
- 后端来源:PocketBase 的
认证流程
用户在登录页面通过“超级管理员登录”勾选项决定认证路径:
- 勾选:调用
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 != ""或更细粒度的规则。