Files
makemd/docs/ARCHIVE/02_Backend/07_RBAC_Design.md
wurenzhi 1b14947e7b refactor: 优化代码结构和类型定义
feat(types): 添加express.d.ts类型引用
style: 格式化express.d.ts中的接口定义
refactor: 移除未使用的AntFC类型导入
chore: 删除自动生成的.umi-production文件
feat: 添加店铺管理相关表和初始化脚本
docs: 更新安全规则和交互指南文档
refactor: 统一使用FC类型替代React.FC
perf: 优化图表组件导入方式
style: 添加.prettierrc配置文件
refactor: 调整组件导入顺序和结构
feat: 添加平台库存管理路由
fix: 修复订单同步时的库存检查逻辑
docs: 更新RBAC设计和租户管理文档
refactor: 优化部门控制器代码
2026-03-30 01:20:57 +08:00

536 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 权限系统设计文档 (Crawlful Hub)
> **定位**Crawlful Hub 权限系统设计文档 - 定义基于角色的访问控制RBAC和数据级权限。
> **更新日期**: 2026-03-18
> **最高优先级参考**: [Service_Design.md](./Service_Design.md)
---
## 1. 权限系统概述
### 1.1 核心概念
- **角色Role**:一组权限的集合
- **权限Permission**:对资源的操作许可
- **用户User**:系统的使用者
- **资源Resource**:系统中的对象,如商品、订单、用户等
- **数据级权限**:基于数据属性的访问控制
### 1.2 重要性
良好的权限系统可以:
- 保护系统安全
- 确保数据隐私
- 实现职责分离
- 满足合规要求
- 提供可审计性
---
## 2. RBAC 模型
### 2.1 角色定义
| 角色 | 描述 | 权限范围 |
|------|------|----------|
| **ADMIN** | 系统管理员 | 所有资源的所有操作 |
| **MANAGER** | 运营主管 | 大部分资源的管理操作 |
| **OPERATOR** | 运营专员 | 基础运营操作 |
| **FINANCE** | 财务主管 | 财务相关操作 |
| **SOURCING** | 采购专家 | 采购相关操作 |
| **LOGISTICS** | 物流专家 | 物流相关操作 |
| **ANALYST** | 数据分析师 | 数据分析相关操作 |
### 2.2 权限定义
| 权限 | 描述 | 适用资源 |
|------|------|----------|
| **CREATE** | 创建资源 | 所有资源 |
| **READ** | 读取资源 | 所有资源 |
| **UPDATE** | 更新资源 | 所有资源 |
| **DELETE** | 删除资源 | 所有资源 |
| **APPROVE** | 审批操作 | 订单、结算等 |
| **EXPORT** | 导出数据 | 报表、数据等 |
| **IMPORT** | 导入数据 | 商品、用户等 |
### 2.3 权限分配
**示例**
```typescript
// 角色权限映射
const rolePermissions = {
ADMIN: ['*'], // 所有权限
MANAGER: [
'CREATE:product', 'READ:product', 'UPDATE:product', 'DELETE:product',
'CREATE:order', 'READ:order', 'UPDATE:order', 'APPROVE:order',
'READ:report', 'EXPORT:report'
],
OPERATOR: [
'READ:product', 'UPDATE:product',
'READ:order', 'UPDATE:order'
],
FINANCE: [
'READ:order', 'READ:settlement', 'APPROVE:settlement',
'READ:report', 'EXPORT:report'
],
SOURCING: [
'CREATE:product', 'READ:product', 'UPDATE:product',
'READ:supplier', 'CREATE:supplier', 'UPDATE:supplier'
],
LOGISTICS: [
'READ:order', 'UPDATE:order',
'READ:inventory', 'UPDATE:inventory'
],
ANALYST: [
'READ:report', 'EXPORT:report'
]
};
```
---
## 3. 数据级权限
### 3.1 定义
数据级权限是指基于数据属性的访问控制,确保用户只能访问和操作与自己相关的数据。
### 3.2 实现方法
#### 3.2.1 租户隔离
**定义**:不同租户的数据相互隔离
**实现**
- 在所有数据表中添加 `tenantId` 字段
- 在所有查询中默认带上 `tenantId` 过滤
- 确保跨租户操作的安全性
**示例**
```typescript
// 数据访问层
class ProductRepository {
async findAll(tenantId: string, params?: any): Promise<Product[]> {
return await Product.findAll({
where: {
tenantId,
...params
}
});
}
async findById(id: string, tenantId: string): Promise<Product | null> {
return await Product.findOne({
where: {
id,
tenantId
}
});
}
}
```
#### 3.2.2 店铺隔离
**定义**:同一租户下不同店铺的数据相互隔离
**实现**
- 在相关数据表中添加 `shopId` 字段
- 在查询中根据用户的店铺权限过滤
- 确保用户只能访问自己有权限的店铺数据
**示例**
```typescript
// 权限服务
class RBACService {
async checkShopAccess(userId: string, shopId: string): Promise<boolean> {
const user = await this.userRepository.findById(userId);
const userShops = await this.userShopRepository.findByUserId(userId);
return userShops.some(us => us.shopId === shopId) || user.role === 'ADMIN';
}
}
// 订单服务
class OrderService {
async getOrders(userId: string, params?: any): Promise<Order[]> {
const user = await this.userRepository.findById(userId);
if (user.role === 'ADMIN') {
return await this.orderRepository.findAll(params);
}
const userShops = await this.userShopRepository.findByUserId(userId);
const shopIds = userShops.map(us => us.shopId);
return await this.orderRepository.findAll({
...params,
shopId: shopIds
});
}
}
```
#### 3.2.3 字段级权限
**定义**:基于字段的访问控制
**实现**
- 定义字段级权限规则
- 在返回数据时过滤敏感字段
- 确保用户只能看到和修改自己有权限的字段
**示例**
```typescript
// 字段级权限
const fieldPermissions = {
ADMIN: {
product: ['*'], // 所有字段
user: ['*']
},
MANAGER: {
product: ['id', 'name', 'price', 'stock'],
user: ['id', 'name', 'email']
},
OPERATOR: {
product: ['id', 'name', 'price'],
user: ['id', 'name']
}
};
// 数据过滤
function filterFields(data: any, fields: string[]): any {
if (fields.includes('*')) {
return data;
}
const filtered: any = {};
fields.forEach(field => {
if (data[field] !== undefined) {
filtered[field] = data[field];
}
});
return filtered;
}
```
### 3.3 最佳实践
- **默认带租户ID**:所有查询默认带 `tenantId` 过滤
- **权限检查前置**:在业务逻辑开始前检查权限
- **统一权限服务**:使用统一的权限服务处理权限检查
- **缓存权限**:缓存用户权限,提高性能
- **审计日志**:记录权限相关操作的审计日志
---
## 4. 权限验证
### 4.1 实现方法
#### 4.1.1 中间件验证
**适用场景**API 路由权限验证
**实现**
- 创建权限验证中间件
- 在路由中应用中间件
- 验证用户是否有权限访问资源
**示例**
```typescript
// 权限中间件
const authorize = (requiredPermission: string) => {
return (req, res, next) => {
const user = req.user;
if (!user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (!user.permissions.includes(requiredPermission) && user.role !== 'ADMIN') {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
// 使用
app.get('/products', authorize('READ:product'), productController.getProducts);
app.post('/products', authorize('CREATE:product'), productController.createProduct);
```
#### 4.1.2 服务层验证
**适用场景**:业务逻辑权限验证
**实现**
- 在服务层检查权限
- 验证用户是否有权限操作资源
- 验证用户是否有权限访问数据
**示例**
```typescript
async updateProduct(productId: string, updates: Partial<Product>, userId: string): Promise<Product> {
// 检查操作权限
if (!this.rbacService.hasPermission(userId, 'UPDATE:product')) {
throw new ForbiddenException('You do not have permission to update products');
}
// 获取商品
const product = await this.productRepository.findById(productId);
if (!product) {
throw new NotFoundException('Product not found');
}
// 检查数据权限
if (!this.rbacService.hasDataAccess(userId, product.tenantId, product.shopId)) {
throw new ForbiddenException('You do not have access to this product');
}
// 更新商品
Object.assign(product, updates);
return await this.productRepository.save(product);
}
```
### 4.2 最佳实践
- **多层验证**:在中间件和服务层都进行权限验证
- **明确的错误信息**:返回清晰的权限错误信息
- **权限缓存**:缓存用户权限,提高验证性能
- **定期权限检查**:定期检查权限配置的正确性
---
## 5. 权限管理
### 5.1 角色管理
- **创建角色**:定义新角色
- **修改角色**:修改角色的权限
- **删除角色**:删除不需要的角色
- **分配角色**:为用户分配角色
- **自定义角色**:允许租户管理员创建自定义角色和权限组合
- **权限细粒度控制**:更细致的功能权限划分
- **权限继承可视化**:清晰展示权限继承关系
- **权限审计**:记录权限变更历史
### 5.2 权限管理
- **定义权限**:定义新的权限
- **分配权限**:为角色分配权限
- **回收权限**:从角色中回收权限
### 5.3 用户管理
- **创建用户**:创建新用户并分配角色
- **修改用户**:修改用户的角色和权限
- **删除用户**:删除用户
- **禁用用户**:暂时禁用用户
- **批量操作支持**:批量添加、更新用户
### 5.4 部门管理
- **部门层级管理**:支持多级部门结构的创建和管理
- **部门负责人设置**:自动为部门负责人分配管理权限
- **部门转移**:支持用户在不同部门间的转移
- **部门统计**:按部门统计用户和店铺数量
---
## 6. 安全考虑
### 6.1 防止权限提升
- **最小权限原则**:用户只获得必要的权限
- **权限审计**:定期审计权限配置
- **权限边界**:明确权限的边界
### 6.2 防止数据泄露
- **数据加密**:加密敏感数据
- **访问控制**:严格控制数据访问
- **审计日志**:记录数据访问日志
### 6.3 防止暴力破解
- **密码策略**:强密码要求
- **登录限制**:限制登录尝试次数
- **验证码**:使用验证码防止暴力破解
---
## 7. 测试策略
### 7.1 单元测试
- 测试权限验证逻辑
- 测试角色权限映射
- 测试数据级权限过滤
### 7.2 集成测试
- 测试完整的权限流程
- 测试不同角色的访问控制
- 测试数据级权限的有效性
### 7.3 安全测试
- 测试权限提升攻击
- 测试数据泄露风险
- 测试暴力破解防护
---
## 8. 相关文档
- [Service_Design.md](./Service_Design.md)
- [Data_Consistency.md](./Data_Consistency.md)
- [API_Specs](./API_Specs/)
---
*本文档基于服务设计文档,最后更新: 2026-03-18*
---
## 9. 组织层级与数据范围Organization & Data Scope
### 9.1 组织层级模型
**核心原则**
> ❗ 权限 = 能做什么Permission
> ❗ 数据范围 = 能操作谁的数据Scope
> 👉 两者必须同时存在
**多租户层级结构**
```
平台Platform
商户/公司Tenant/Organization
组织结构Org Tree
├── 部门A主管
│ ├── 组A1组长
│ │ ├── 员工1
│ │ └── 员工2
│ └── 组A2组长
│ └── 员工3
└── 部门B主管
└── ...
```
### 9.2 数据范围定义
| 范围类型 | 英文 | 说明 | SQL过滤条件 |
|---------|------|------|------------|
| **SELF** | Self | 只看自己 | `WHERE created_by = {userId}` |
| **TEAM** | Team | 看自己组 | `WHERE team_id IN ({userTeams})` |
| **DEPT** | Department | 看自己部门 | `WHERE dept_id IN ({userDepts})` |
| **ORG** | Organization | 看整个公司 | `WHERE tenant_id = {tenantId}` |
| **ALL** | All | 全平台(超管) | 无过滤 |
### 9.3 数据范围实现
```typescript
interface DataScopeContext {
userId: string;
tenantId: string;
orgId: string;
scopeType: 'SELF' | 'TEAM' | 'DEPT' | 'ORG' | 'ALL';
}
class DataScopeService {
async buildScopeQuery(ctx: DataScopeContext): Promise<WhereClause> {
switch (ctx.scopeType) {
case 'SELF':
return { created_by: ctx.userId };
case 'TEAM':
const teams = await this.getUserTeams(ctx.userId);
return { team_id: { in: teams } };
case 'DEPT':
const depts = await this.getUserDepts(ctx.userId);
return { dept_id: { in: depts } };
case 'ORG':
return { tenant_id: ctx.tenantId };
case 'ALL':
return {};
}
}
}
```
### 9.4 店铺角色权限
| 角色 | 描述 | 权限范围 |
|------|------|----------|
| **owner** | 拥有者 | 删除店铺、管理授权、管理成员、所有权限 |
| **admin** | 管理员 | 管理商品、管理价格、管理订单、不可删除店铺 |
| **operator** | 运营 | 刊登、改价、查看数据 |
| **viewer** | 只读 | 查看数据、不可操作 |
### 9.5 授权模型
**核心原则**
> ❗ 授权属于店铺,不属于用户
> ❗ 店铺属于主体Owner用户只是被授权使用
**店铺授权结构**
```
Organization公司
Shop店铺
Auth授权
User使用者
```
**授权类型**
| 类型 | 适用平台 | 存储内容 |
|------|----------|----------|
| **API授权** | Shopify、Amazon | access_token, refresh_token, expire_time |
| **Agent授权** | TikTok、Shopee | cookies, proxy, device_id, user_agent |
### 9.6 权限校验中间件
```typescript
const authorize = (requiredPermission: string) => {
return async (req, res, next) => {
const user = req.user;
if (!user) {
return res.status(401).json({ error: 'Unauthorized' });
}
const hasPermission = await rbacService.checkPermission(
user.id,
requiredPermission,
req.params.shopId
);
if (!hasPermission) {
return res.status(403).json({ error: 'Forbidden' });
}
const scopeQuery = await dataScopeService.buildScopeQuery({
userId: user.id,
tenantId: user.tenantId,
orgId: user.orgId,
scopeType: user.dataScope
});
req.scopeQuery = scopeQuery;
next();
};
};
```