698 lines
26 KiB
Markdown
698 lines
26 KiB
Markdown
|
|
# 多角色权限设计方案(P1)
|
|||
|
|
|
|||
|
|
- 版本:v1.0
|
|||
|
|
- 日期:2026-04-02
|
|||
|
|
- 状态:设计稿(已修复)
|
|||
|
|
- 依赖:
|
|||
|
|
- `docs/token_runtime_minimal_spec_v1.md`(TOK-001)
|
|||
|
|
- `docs/token_auth_middleware_design_v1_2026-03-29.md`(TOK-002)
|
|||
|
|
- `docs/llm_gateway_prd_v1_2026-03-25.md`
|
|||
|
|
- 目标:实现 PRD P1 "多角色权限"需求
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 背景与目标
|
|||
|
|
|
|||
|
|
### 1.1 业务背景
|
|||
|
|
|
|||
|
|
LLM Gateway 平台需要支持多类用户角色,满足不同的使用场景:
|
|||
|
|
|
|||
|
|
1. **平台管理员** - 负责组织级策略、预算、权限管理
|
|||
|
|
2. **AI 应用开发者** - 负责接入模型与业务落地
|
|||
|
|
3. **财务/运营负责人** - 负责成本追踪、对账与预算控制
|
|||
|
|
4. **供应方** - 拥有多余LLM配额的个人或企业(平台用户)
|
|||
|
|
5. **需求方** - 需要LLM调用能力的企业/开发者
|
|||
|
|
|
|||
|
|
### 1.2 设计目标
|
|||
|
|
|
|||
|
|
1. **角色扩展**:在现有 `owner/viewer/admin` 三角色基础上扩展,支持更多业务场景
|
|||
|
|
2. **权限细分**:支持细粒度的 scope 权限控制
|
|||
|
|
3. **层级清晰**:建立的角色继承/层级关系
|
|||
|
|
4. **API兼容**:保持与现有 SUP-004~SUP-008 链路一致
|
|||
|
|
5. **可扩展**:支持未来新增角色和权限
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 现有权限模型分析
|
|||
|
|
|
|||
|
|
### 2.1 现有角色体系(TOK-001)
|
|||
|
|
|
|||
|
|
| 角色 | 等级 | 能力 | 约束 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| admin | 3 | 风控与审计管理 | 仅平台内部可用 |
|
|||
|
|
| owner | 2 | 管理供应侧账号、套餐、结算 | 不可读取上游凭证明文 |
|
|||
|
|
| viewer | 1 | 只读查询 | 不可执行写操作 |
|
|||
|
|
|
|||
|
|
### 2.2 现有 JWT Token Claims 结构
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type TokenClaims struct {
|
|||
|
|
jwt.RegisteredClaims
|
|||
|
|
SubjectID string `json:"subject_id"` // 用户主体ID
|
|||
|
|
Role string `json:"role"` // 角色: admin/owner/viewer
|
|||
|
|
Scope []string `json:"scope"` // 授权范围列表
|
|||
|
|
TenantID int64 `json:"tenant_id"` // 租户ID
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 现有中间件链路(TOK-002)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
RequestIdMiddleware
|
|||
|
|
↓
|
|||
|
|
QueryKeyRejectMiddleware
|
|||
|
|
↓
|
|||
|
|
BearerExtractMiddleware
|
|||
|
|
↓
|
|||
|
|
TokenVerifyMiddleware
|
|||
|
|
↓
|
|||
|
|
TokenStatusCheckMiddleware
|
|||
|
|
↓
|
|||
|
|
ScopeRoleAuthzMiddleware ← 权限校验
|
|||
|
|
↓
|
|||
|
|
AuditEmitMiddleware
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 多角色权限设计方案
|
|||
|
|
|
|||
|
|
### 3.1 角色定义
|
|||
|
|
|
|||
|
|
#### 3.1.1 平台侧角色(Platform Roles)
|
|||
|
|
|
|||
|
|
| 角色 | 代码 | 层级 | 说明 | 继承关系 |
|
|||
|
|
|------|------|------|------|----------|
|
|||
|
|
| 超级管理员 | `super_admin` | 100 | 平台最高权限,仅平台运营方可用 | - |
|
|||
|
|
| 组织管理员 | `org_admin` | 50 | 组织级管理,管理本组织所有资源 | 显式配置(拥有operator+finops+developer+viewer所有scope) |
|
|||
|
|
| 运维人员 | `operator` | 30 | 系统运维与配置 | 显式配置(拥有viewer所有scope + platform:write等) |
|
|||
|
|
| 开发者 | `developer` | 20 | AI应用开发者,接入模型与业务落地 | 继承 viewer |
|
|||
|
|
| 财务人员 | `finops` | 20 | 成本追踪、对账与预算控制 | 继承 viewer |
|
|||
|
|
| 查看者 | `viewer` | 10 | 只读查询 | - |
|
|||
|
|
|
|||
|
|
**说明**:
|
|||
|
|
1. 继承关系仅用于权限聚合,代表"子角色拥有父角色所有scope + 自身额外scope"
|
|||
|
|
2. `org_admin` 显式配置拥有 `operator` + `finops` + `developer` + `viewer` 的所有scope
|
|||
|
|
3. `operator` 显式配置拥有 `viewer` 所有scope + `platform:write` 等权限
|
|||
|
|
4. 层级数值仅用于权限优先级判断,不影响继承关系
|
|||
|
|
|
|||
|
|
#### 3.1.2 供应侧角色(Supply Roles)
|
|||
|
|
|
|||
|
|
| 角色 | 代码 | 层级 | 说明 | 继承关系 |
|
|||
|
|
|------|------|------|------|----------|
|
|||
|
|
| 供应方管理员 | `supply_admin` | 40 | 供应侧全面管理 | 显式配置(拥有supply_operator+supply_finops所有scope) |
|
|||
|
|
| 供应方运维 | `supply_operator` | 30 | 套餐管理、额度配置 | 显式配置(拥有supply_viewer所有scope + supply:package:write等) |
|
|||
|
|
| 供应方财务 | `supply_finops` | 20 | 收益结算、对账 | 继承 supply_viewer |
|
|||
|
|
| 供应方查看者 | `supply_viewer` | 10 | 只读查询 | - |
|
|||
|
|
|
|||
|
|
#### 3.1.3 需求侧角色(Consumer Roles)
|
|||
|
|
|
|||
|
|
| 角色 | 代码 | 层级 | 说明 | 继承关系 |
|
|||
|
|
|------|------|------|------|----------|
|
|||
|
|
| 需求方管理员 | `consumer_admin` | 40 | 需求侧全面管理 | 显式配置(拥有consumer_operator所有scope) |
|
|||
|
|
| 需求方运维 | `consumer_operator` | 30 | API Key管理、调用配置 | 显式配置(拥有consumer_viewer所有scope + consumer:apikey:*等) |
|
|||
|
|
| 需求方查看者 | `consumer_viewer` | 10 | 只读查询 | - |
|
|||
|
|
|
|||
|
|
### 3.2 角色层级关系图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────┐
|
|||
|
|
│ super_admin │ (层级100)
|
|||
|
|
└──────┬──────┘
|
|||
|
|
│ 权限聚合
|
|||
|
|
▼
|
|||
|
|
┌─────────────┐
|
|||
|
|
│ org_admin │ (层级50)
|
|||
|
|
└──────┬──────┘
|
|||
|
|
│ 显式配置(聚合operator+developer+finops+viewer scope)
|
|||
|
|
┌────────────┼────────────┐
|
|||
|
|
▼ ▼ ▼
|
|||
|
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|||
|
|
│ operator │ │developer │ │ finops │ (层级20-30)
|
|||
|
|
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
|||
|
|
│ │ │
|
|||
|
|
│ 显式配置 │ 继承 │ 继承
|
|||
|
|
│ (+viewer) │ (+viewer) │ (+viewer)
|
|||
|
|
▼ ▼ ▼
|
|||
|
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|||
|
|
│ viewer │ │ viewer │ │ viewer │ (层级10)
|
|||
|
|
└──────────┘ └──────────┘ └──────────┘
|
|||
|
|
|
|||
|
|
─────────────────────────────────────────
|
|||
|
|
|
|||
|
|
┌──────────┐ ┌──────────────┐
|
|||
|
|
│supply_ad │────│consumer_adm │
|
|||
|
|
│ min │ │ in │ (层级40)
|
|||
|
|
└────┬─────┘ └──────┬───────┘
|
|||
|
|
│ 显式配置 │ 显式配置
|
|||
|
|
│ (+operator │ (+operator
|
|||
|
|
│ +finops) │ +viewer)
|
|||
|
|
▼ ▼
|
|||
|
|
┌──────────┐ ┌──────────────┐
|
|||
|
|
│supply_op │ │consumer_op │
|
|||
|
|
│ erator │ │ erator │ (层级30)
|
|||
|
|
└────┬─────┘ └──────┬───────┘
|
|||
|
|
│ 显式配置 │ 显式配置
|
|||
|
|
│ (+viewer) │ (+viewer)
|
|||
|
|
▼ ▼
|
|||
|
|
┌──────────┐ ┌──────────────┐
|
|||
|
|
│supply_vi │ │consumer_vi │
|
|||
|
|
│ ewer │ │ ewer │ (层级10)
|
|||
|
|
└──────────┘ └──────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**继承关系说明**:
|
|||
|
|
- 继承 = 子角色拥有父角色所有 scope + 自身额外 scope
|
|||
|
|
- 显式配置 = 直接授予特定 scope 列表(等效于显式继承但更清晰)
|
|||
|
|
- supply_admin/consumer_admin = 拥有该类别下所有子角色 scope
|
|||
|
|
- operator/developer/finops = 拥有 viewer 所有 scope + 各自额外 scope
|
|||
|
|
|
|||
|
|
### 3.3 Scope 权限定义
|
|||
|
|
|
|||
|
|
#### 3.3.1 Platform Scope
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 |
|
|||
|
|
|-------|------|----------|
|
|||
|
|
| `platform:read` | 读取平台配置 | viewer+ |
|
|||
|
|
| `platform:write` | 修改平台配置 | operator+ |
|
|||
|
|
| `platform:admin` | 平台级管理 | org_admin+ |
|
|||
|
|
| `platform:audit:read` | 读取审计日志 | operator+ |
|
|||
|
|
| `platform:audit:export` | 导出审计日志 | org_admin+ |
|
|||
|
|
|
|||
|
|
#### 3.3.2 Tenant Scope
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 | 备注 |
|
|||
|
|
|-------|------|----------|------|
|
|||
|
|
| `tenant:read` | 读取租户信息 | viewer+ | |
|
|||
|
|
| `tenant:write` | 修改租户配置 | operator+ | |
|
|||
|
|
| `tenant:member:manage` | 管理租户成员 | org_admin | |
|
|||
|
|
| `tenant:billing:write` | 修改账单设置 | org_admin | |
|
|||
|
|
|
|||
|
|
#### 3.3.3 Supply Scope
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 | 备注 |
|
|||
|
|
|-------|------|----------|------|
|
|||
|
|
| `supply:account:read` | 读取供应账号 | supply_viewer+ | |
|
|||
|
|
| `supply:account:write` | 管理供应账号 | supply_operator+ | |
|
|||
|
|
| `supply:package:read` | 读取套餐信息 | supply_viewer+ | |
|
|||
|
|
| `supply:package:write` | 管理套餐 | supply_operator+ | |
|
|||
|
|
| `supply:package:publish` | 发布套餐 | supply_operator+ | |
|
|||
|
|
| `supply:package:offline` | 下架套餐 | supply_operator+ | |
|
|||
|
|
| `supply:settlement:withdraw` | 提现 | supply_admin | |
|
|||
|
|
| `supply:credential:manage` | 管理凭证 | supply_admin | |
|
|||
|
|
|
|||
|
|
#### 3.3.4 Consumer Scope
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 | 备注 |
|
|||
|
|
|-------|------|----------|------|
|
|||
|
|
| `consumer:account:read` | 读取账户信息 | consumer_viewer+ | |
|
|||
|
|
| `consumer:account:write` | 管理账户 | consumer_operator+ | |
|
|||
|
|
| `consumer:apikey:create` | 创建API Key | consumer_operator+ | |
|
|||
|
|
| `consumer:apikey:read` | 读取API Key | consumer_viewer+ | |
|
|||
|
|
| `consumer:apikey:revoke` | 吊销API Key | consumer_operator+ | |
|
|||
|
|
| `consumer:usage:read` | 读取使用量 | consumer_viewer+ | |
|
|||
|
|
|
|||
|
|
#### 3.3.5 Billing Scope(统一)
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 | user_type限定 |
|
|||
|
|
|-------|------|----------|---------------|
|
|||
|
|
| `billing:read` | 读取账单 | finops+, supply_finops+, consumer_viewer+ | 通过user_type区分数据范围 |
|
|||
|
|
| `billing:write` | 修改账单设置 | org_admin | |
|
|||
|
|
|
|||
|
|
**说明**:
|
|||
|
|
- 原有 `tenant:billing:read`、`supply:settlement:read`、`consumer:billing:read` 统一为 `billing:read`
|
|||
|
|
- 通过 TokenClaims.user_type 字段限定数据范围:platform用户看租户账单,supply用户看供应结算,consumer用户看需求账单
|
|||
|
|
- 原 scope 名称保留作为 deprecated alias
|
|||
|
|
|
|||
|
|
#### 3.3.6 Router Scope(网关转发)
|
|||
|
|
|
|||
|
|
| Scope | 说明 | 授予角色 |
|
|||
|
|
|-------|------|----------|
|
|||
|
|
| `router:invoke` | 调用模型 | 所有认证用户 |
|
|||
|
|
| `router:model:list` | 列出可用模型 | viewer+ |
|
|||
|
|
| `router:model:config` | 配置路由策略 | operator+ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. API 路由权限映射
|
|||
|
|
|
|||
|
|
### 4.1 Platform API
|
|||
|
|
|
|||
|
|
| API路径 | 方法 | 所需Scope | 所需角色 |
|
|||
|
|
|---------|------|-----------|----------|
|
|||
|
|
| `/api/v1/platform/info` | GET | `platform:read` | viewer+ |
|
|||
|
|
| `/api/v1/platform/config` | GET | `platform:read` | viewer+ |
|
|||
|
|
| `/api/v1/platform/config` | PUT | `platform:write` | operator+ |
|
|||
|
|
| `/api/v1/platform/tenants` | GET | `tenant:read` | viewer+ |
|
|||
|
|
| `/api/v1/platform/tenants` | POST | `tenant:write` | operator+ |
|
|||
|
|
| `/api/v1/platform/audit/events` | GET | `platform:audit:read` | operator+ |
|
|||
|
|
| `/api/v1/platform/audit/events/export` | POST | `platform:audit:export` | org_admin+ |
|
|||
|
|
|
|||
|
|
### 4.2 Supply API(与 SUP-004~SUP-008 保持一致)
|
|||
|
|
|
|||
|
|
| API路径 | 方法 | 所需Scope | 所需角色 |
|
|||
|
|
|---------|------|-----------|----------|
|
|||
|
|
| `/api/v1/supply/accounts` | GET | `supply:account:read` | supply_viewer+ |
|
|||
|
|
| `/api/v1/supply/accounts` | POST | `supply:account:write` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/accounts/:id` | PUT | `supply:account:write` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/accounts/:id/verify` | POST | `supply:account:write` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/packages` | GET | `supply:package:read` | supply_viewer+ |
|
|||
|
|
| `/api/v1/supply/packages` | POST | `supply:package:write` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/packages/:id/publish` | POST | `supply:package:publish` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/packages/:id/offline` | POST | `supply:package:offline` | supply_operator+ |
|
|||
|
|
| `/api/v1/supply/settlements` | GET | `billing:read` | supply_finops+ |
|
|||
|
|
| `/api/v1/supply/settlements/withdraw` | POST | `supply:settlement:withdraw` | supply_admin |
|
|||
|
|
| `/api/v1/supply/billing` | GET | `billing:read` | supply_finops+ |
|
|||
|
|
|
|||
|
|
**Deprecated Alias 说明**:
|
|||
|
|
- `/api/v1/supplier/*` 路径仅作为历史兼容别名保留
|
|||
|
|
- 新接口禁止使用 `/supplier` 前缀
|
|||
|
|
- deprecated alias 响应体应包含 `deprecation_notice` 字段提示迁移
|
|||
|
|
- S2 阶段评估 alias 下线时间
|
|||
|
|
|
|||
|
|
### 4.3 Consumer API
|
|||
|
|
|
|||
|
|
| API路径 | 方法 | 所需Scope | 所需角色 |
|
|||
|
|
|---------|------|-----------|----------|
|
|||
|
|
| `/api/v1/consumer/account` | GET | `consumer:account:read` | consumer_viewer+ |
|
|||
|
|
| `/api/v1/consumer/account` | PUT | `consumer:account:write` | consumer_operator+ |
|
|||
|
|
| `/api/v1/consumer/apikeys` | GET | `consumer:apikey:read` | consumer_viewer+ |
|
|||
|
|
| `/api/v1/consumer/apikeys` | POST | `consumer:apikey:create` | consumer_operator+ |
|
|||
|
|
| `/api/v1/consumer/apikeys/:id/revoke` | POST | `consumer:apikey:revoke` | consumer_operator+ |
|
|||
|
|
| `/api/v1/consumer/usage` | GET | `consumer:usage:read` | consumer_viewer+ |
|
|||
|
|
| `/api/v1/consumer/billing` | GET | `billing:read` | consumer_viewer+ |
|
|||
|
|
|
|||
|
|
### 4.4 Router API(网关调用)
|
|||
|
|
|
|||
|
|
| API路径 | 方法 | 所需Scope | 所需角色 |
|
|||
|
|
|---------|------|-----------|----------|
|
|||
|
|
| `/v1/chat/completions` | POST | `router:invoke` | 所有认证用户 |
|
|||
|
|
| `/v1/completions` | POST | `router:invoke` | 所有认证用户 |
|
|||
|
|
| `/v1/embeddings` | POST | `router:invoke` | 所有认证用户 |
|
|||
|
|
| `/v1/models` | GET | `router:model:list` | viewer+ |
|
|||
|
|
| `/api/v1/router/models` | GET | `router:model:list` | viewer+ |
|
|||
|
|
| `/api/v1/router/policies` | GET | `router:model:config` | operator+ |
|
|||
|
|
| `/api/v1/router/policies` | PUT | `router:model:config` | operator+ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 数据模型扩展
|
|||
|
|
|
|||
|
|
### 5.1 Role 定义表(iam_roles)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE iam_roles (
|
|||
|
|
id BIGSERIAL PRIMARY KEY,
|
|||
|
|
role_code VARCHAR(50) NOT NULL UNIQUE, -- super_admin, org_admin, operator, developer, finops, viewer
|
|||
|
|
role_name VARCHAR(100) NOT NULL,
|
|||
|
|
role_type VARCHAR(20) NOT NULL, -- platform, supply, consumer
|
|||
|
|
parent_role_id BIGINT REFERENCES iam_roles(id), -- 继承关系
|
|||
|
|
level INT NOT NULL DEFAULT 0, -- 权限层级
|
|||
|
|
description TEXT,
|
|||
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|||
|
|
|
|||
|
|
-- 审计字段(符合 database_domain_model_and_governance v1 规范)
|
|||
|
|
request_id VARCHAR(64), -- 请求追踪ID
|
|||
|
|
created_ip INET, -- 创建者IP
|
|||
|
|
updated_ip INET, -- 更新者IP
|
|||
|
|
version INT DEFAULT 1, -- 乐观锁版本号
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_iam_roles_code ON iam_roles(role_code);
|
|||
|
|
CREATE INDEX idx_iam_roles_type ON iam_roles(role_type);
|
|||
|
|
CREATE INDEX idx_iam_roles_request_id ON iam_roles(request_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 Scope 定义表(iam_scopes)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE iam_scopes (
|
|||
|
|
id BIGSERIAL PRIMARY KEY,
|
|||
|
|
scope_code VARCHAR(100) NOT NULL UNIQUE, -- platform:read, supply:account:write
|
|||
|
|
scope_name VARCHAR(100) NOT NULL,
|
|||
|
|
scope_type VARCHAR(50) NOT NULL, -- platform, supply, consumer, router
|
|||
|
|
description TEXT,
|
|||
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|||
|
|
|
|||
|
|
-- 审计字段(符合 database_domain_model_and_governance v1 规范)
|
|||
|
|
request_id VARCHAR(64), -- 请求追踪ID
|
|||
|
|
created_ip INET, -- 创建者IP
|
|||
|
|
updated_ip INET, -- 更新者IP
|
|||
|
|
version INT DEFAULT 1, -- 乐观锁版本号
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_iam_scopes_code ON iam_scopes(scope_code);
|
|||
|
|
CREATE INDEX idx_iam_scopes_request_id ON iam_scopes(request_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3 角色-Scope 关联表(iam_role_scopes)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE iam_role_scopes (
|
|||
|
|
id BIGSERIAL PRIMARY KEY,
|
|||
|
|
role_id BIGINT NOT NULL REFERENCES iam_roles(id),
|
|||
|
|
scope_id BIGINT NOT NULL REFERENCES iam_scopes(id),
|
|||
|
|
|
|||
|
|
-- 审计字段(符合 database_domain_model_and_governance v1 规范)
|
|||
|
|
request_id VARCHAR(64), -- 请求追踪ID
|
|||
|
|
created_ip INET, -- 创建者IP
|
|||
|
|
version INT DEFAULT 1, -- 乐观锁版本号
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|||
|
|
UNIQUE(role_id, scope_id)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_iam_role_scopes_role ON iam_role_scopes(role_id);
|
|||
|
|
CREATE INDEX idx_iam_role_scopes_scope ON iam_role_scopes(scope_id);
|
|||
|
|
CREATE INDEX idx_iam_role_scopes_request_id ON iam_role_scopes(request_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.4 用户-角色关联表(iam_user_roles)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE iam_user_roles (
|
|||
|
|
id BIGSERIAL PRIMARY KEY,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
role_id BIGINT NOT NULL REFERENCES iam_roles(id),
|
|||
|
|
tenant_id BIGINT, -- 租户范围(NULL表示全局)
|
|||
|
|
granted_by BIGINT,
|
|||
|
|
granted_at TIMESTAMPTZ DEFAULT NOW(),
|
|||
|
|
expires_at TIMESTAMPTZ, -- 角色过期时间
|
|||
|
|
|
|||
|
|
-- 审计字段(符合 database_domain_model_and_governance v1 规范)
|
|||
|
|
request_id VARCHAR(64), -- 请求追踪ID
|
|||
|
|
created_ip INET, -- 创建者IP
|
|||
|
|
updated_ip INET, -- 更新者IP
|
|||
|
|
version INT DEFAULT 1, -- 乐观锁版本号
|
|||
|
|
|
|||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_iam_user_roles_user ON iam_user_roles(user_id);
|
|||
|
|
CREATE INDEX idx_iam_user_roles_tenant ON iam_user_roles(tenant_id);
|
|||
|
|
CREATE INDEX idx_iam_user_roles_request_id ON iam_user_roles(request_id);
|
|||
|
|
CREATE UNIQUE INDEX idx_iam_user_roles_unique ON iam_user_roles(user_id, role_id, tenant_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.5 扩展 Token Claims
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type TokenClaims struct {
|
|||
|
|
jwt.RegisteredClaims
|
|||
|
|
SubjectID string `json:"subject_id"` // 用户主体ID
|
|||
|
|
Role string `json:"role"` // 主角色
|
|||
|
|
Scope []string `json:"scope"` // 授权范围列表
|
|||
|
|
TenantID int64 `json:"tenant_id"` // 租户ID
|
|||
|
|
UserType string `json:"user_type"` // 用户类型: platform/supply/consumer
|
|||
|
|
Permissions []string `json:"permissions"` // 细粒度权限列表
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 中间件设计
|
|||
|
|
|
|||
|
|
### 6.1 扩展 ScopeRoleAuthzMiddleware
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 扩展后的权限校验逻辑
|
|||
|
|
type AuthzConfig struct {
|
|||
|
|
// 路由-角色映射
|
|||
|
|
RouteRolePolicies map[string]RolePolicy
|
|||
|
|
// 路由-Scope映射
|
|||
|
|
RouteScopePolicies map[string][]string
|
|||
|
|
// 角色层级
|
|||
|
|
RoleHierarchy map[string]int
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type RolePolicy struct {
|
|||
|
|
RequiredLevel int
|
|||
|
|
RequiredRole string
|
|||
|
|
RequiredScope []string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 权限校验逻辑
|
|||
|
|
func (m *AuthMiddleware) ScopeRoleAuthzMiddleware(requiredScope string) func(http.Handler) http.Handler {
|
|||
|
|
return func(next http.Handler) http.Handler {
|
|||
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
claims, ok := r.Context().Value(tokenClaimsKey).(*TokenClaims)
|
|||
|
|
if !ok {
|
|||
|
|
writeAuthError(w, http.StatusUnauthorized, "AUTH_CONTEXT_MISSING", "")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. Scope 校验
|
|||
|
|
if requiredScope != "" && !containsScope(claims.Scope, requiredScope) {
|
|||
|
|
m.emitAuditAndReject(r, w, "AUTH_SCOPE_DENIED", requiredScope, claims)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 角色层级校验(如果配置了角色要求)
|
|||
|
|
if policy, exists := getRoutePolicy(r.URL.Path); exists {
|
|||
|
|
if !checkRolePolicy(claims, policy) {
|
|||
|
|
m.emitAuditAndReject(r, w, "AUTH_ROLE_DENIED", "", claims)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
next.ServeHTTP(w, r)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 新增角色层级中间件
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// RoleHierarchyMiddleware 角色层级校验中间件
|
|||
|
|
// 用于需要特定角色层级的操作
|
|||
|
|
func RoleHierarchyMiddleware(minLevel int) func(http.Handler) http.Handler {
|
|||
|
|
return func(next http.Handler) http.Handler {
|
|||
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
claims := GetTokenClaims(r.Context())
|
|||
|
|
if claims == nil {
|
|||
|
|
writeAuthError(w, http.StatusUnauthorized, "AUTH_CONTEXT_MISSING", "")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if getRoleLevel(claims.Role) < minLevel {
|
|||
|
|
writeAuthError(w, http.StatusForbidden, "AUTH_ROLE_LEVEL_DENIED",
|
|||
|
|
fmt.Sprintf("required role level %d", minLevel))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
next.ServeHTTP(w, r)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 新增跨类型校验中间件
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// UserTypeMiddleware 用户类型校验中间件
|
|||
|
|
// 用于区分 platform/supply/consumer 用户
|
|||
|
|
func UserTypeMiddleware(allowedTypes ...string) func(http.Handler) http.Handler {
|
|||
|
|
return func(next http.Handler) http.Handler {
|
|||
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
claims := GetTokenClaims(r.Context())
|
|||
|
|
if claims == nil {
|
|||
|
|
writeAuthError(w, http.StatusUnauthorized, "AUTH_CONTEXT_MISSING", "")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if !containsString(allowedTypes, claims.UserType) {
|
|||
|
|
writeAuthError(w, http.StatusForbidden, "AUTH_USER_TYPE_DENIED",
|
|||
|
|
fmt.Sprintf("allowed user types: %v", allowedTypes))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
next.ServeHTTP(w, r)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 错误码扩展
|
|||
|
|
|
|||
|
|
| 错误码 | HTTP状态 | 说明 |
|
|||
|
|
|--------|----------|------|
|
|||
|
|
| `AUTH_SCOPE_DENIED` | 403 | Scope权限不足 |
|
|||
|
|
| `AUTH_ROLE_DENIED` | 403 | 角色权限不足 |
|
|||
|
|
| `AUTH_ROLE_LEVEL_DENIED` | 403 | 角色层级不足 |
|
|||
|
|
| `AUTH_USER_TYPE_DENIED` | 403 | 用户类型不允许 |
|
|||
|
|
| `AUTH_TENANT_MISMATCH` | 403 | 租户上下文不匹配 |
|
|||
|
|
| `AUTH_RESOURCE_OWNER_DENIED` | 403 | 资源所有权校验失败 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 审计事件扩展
|
|||
|
|
|
|||
|
|
| 事件名 | 说明 | 触发场景 |
|
|||
|
|
|--------|------|----------|
|
|||
|
|
| `role.assign` | 角色分配 | 给用户分配角色 |
|
|||
|
|
| `role.revoke` | 角色吊销 | 吊销用户角色 |
|
|||
|
|
| `role.scope.denied` | Scope权限拒绝 | Scope校验失败 |
|
|||
|
|
| `role.hierarchy.denied` | 角色层级拒绝 | 角色层级校验失败 |
|
|||
|
|
| `usertype.denied` | 用户类型拒绝 | 用户类型校验失败 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. API 契约更新
|
|||
|
|
|
|||
|
|
### 9.1 新增角色管理 API
|
|||
|
|
|
|||
|
|
#### GET /api/v1/iam/roles
|
|||
|
|
|
|||
|
|
获取角色列表
|
|||
|
|
|
|||
|
|
**响应:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"roles": [
|
|||
|
|
{
|
|||
|
|
"role_code": "org_admin",
|
|||
|
|
"role_name": "组织管理员",
|
|||
|
|
"role_type": "platform",
|
|||
|
|
"level": 50,
|
|||
|
|
"scopes": ["platform:read", "tenant:read", "tenant:write"]
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### POST /api/v1/iam/users/:userId/roles
|
|||
|
|
|
|||
|
|
分配角色给用户
|
|||
|
|
|
|||
|
|
**请求:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"role_code": "developer",
|
|||
|
|
"tenant_id": 123,
|
|||
|
|
"expires_at": "2026-12-31T23:59:59Z"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### DELETE /api/v1/iam/users/:userId/roles/:roleCode
|
|||
|
|
|
|||
|
|
吊销用户角色
|
|||
|
|
|
|||
|
|
### 9.2 新增 Scope 查询 API
|
|||
|
|
|
|||
|
|
#### GET /api/v1/iam/scopes
|
|||
|
|
|
|||
|
|
获取所有可用Scope
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 向后兼容方案
|
|||
|
|
|
|||
|
|
### 10.1 新旧层级映射表(与TOK-001对齐)
|
|||
|
|
|
|||
|
|
| TOK-001旧层级 | 旧角色代码 | 新角色代码 | 新层级 | 权限变化说明 |
|
|||
|
|
|---------------|------------|------------|--------|--------------|
|
|||
|
|
| 3 | admin | `super_admin` | 100 | 完全对应,平台最高权限 |
|
|||
|
|
| 2 | owner | `supply_admin` | 40 | 权限范围明确为供应侧管理,不含平台运营权限 |
|
|||
|
|
| 1 | viewer | `viewer` | 10 | 完全对应 |
|
|||
|
|
|
|||
|
|
**说明**:
|
|||
|
|
- TOK-001 新角色体系(super_admin/org_admin/operator)专属于平台侧管理
|
|||
|
|
- 原 owner 角色对应 supply_admin(供应侧管理员),职责边界清晰
|
|||
|
|
- 层级数值用于优先级判断,新旧体系独立运作
|
|||
|
|
|
|||
|
|
### 10.2 现有角色映射
|
|||
|
|
|
|||
|
|
| 旧角色 | 新角色 | 说明 |
|
|||
|
|
|--------|--------|------|
|
|||
|
|
| `admin` | `super_admin` | 完全对应,层级100 |
|
|||
|
|
| `owner` | `supply_admin` | 权限范围重新定义为供应侧,不含平台运营权限 |
|
|||
|
|
| `viewer` | `viewer` | 完全对应,层级10 |
|
|||
|
|
|
|||
|
|
**权限边界变化说明**:
|
|||
|
|
- 原 owner 可管理供应侧账号、套餐、结算(对应 supply_admin)
|
|||
|
|
- 原 owner 不可执行平台级操作(由 org_admin/super_admin 专属)
|
|||
|
|
- supply_admin(40) < org_admin(50) 是合理设计,因为 org_admin 管理范围更广
|
|||
|
|
|
|||
|
|
### 10.3 Token 兼容处理
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// RoleMapping 旧角色到新角色的映射
|
|||
|
|
var RoleMapping = map[string]string{
|
|||
|
|
"admin": "super_admin",
|
|||
|
|
"owner": "supply_admin",
|
|||
|
|
// viewer 保持不变
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 在Token验证时自动转换
|
|||
|
|
func normalizeRole(role string) string {
|
|||
|
|
if newRole, exists := RoleMapping[role]; exists {
|
|||
|
|
return newRole
|
|||
|
|
}
|
|||
|
|
return role
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 实施计划
|
|||
|
|
|
|||
|
|
### 11.1 Phase 1: 数据模型扩展
|
|||
|
|
|
|||
|
|
1. 创建 `iam_roles`, `iam_scopes`, `iam_role_scopes`, `iam_user_roles` 表
|
|||
|
|
2. 初始化预定义角色和Scope数据
|
|||
|
|
3. 提供数据迁移脚本
|
|||
|
|
|
|||
|
|
### 11.2 Phase 2: 中间件扩展
|
|||
|
|
|
|||
|
|
1. 扩展 `ScopeRoleAuthzMiddleware` 支持新角色层级
|
|||
|
|
2. 新增 `RoleHierarchyMiddleware`
|
|||
|
|
3. 新增 `UserTypeMiddleware`
|
|||
|
|
4. 更新 Token Claims 结构
|
|||
|
|
|
|||
|
|
### 11.3 Phase 3: API 实现
|
|||
|
|
|
|||
|
|
1. 实现角色管理 API
|
|||
|
|
2. 实现 Scope 查询 API
|
|||
|
|
3. 更新现有 API 的权限校验
|
|||
|
|
|
|||
|
|
### 11.4 Phase 4: 向后兼容
|
|||
|
|
|
|||
|
|
1. 实现角色映射逻辑
|
|||
|
|
2. 提供迁移指导文档
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 验收标准
|
|||
|
|
|
|||
|
|
1. [ ] 角色层级清晰:super_admin > org_admin > operator/developer/finops > viewer
|
|||
|
|
2. [ ] Scope权限校验正确:精确匹配路由与所需Scope
|
|||
|
|
3. [ ] 继承关系正确:子角色自动继承父角色Scope
|
|||
|
|
4. [ ] 向后兼容:现有 owner/viewer/admin 角色正常工作
|
|||
|
|
5. [ ] 审计完整:角色变更和权限拒绝事件全量记录
|
|||
|
|
6. [ ] API契约更新:新增角色管理API符合RESTful规范
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 关联文档
|
|||
|
|
|
|||
|
|
- `docs/token_runtime_minimal_spec_v1.md`(TOK-001)
|
|||
|
|
- `docs/token_auth_middleware_design_v1_2026-03-29.md`(TOK-002)
|
|||
|
|
- `docs/llm_gateway_prd_v1_2026-03-25.md`
|
|||
|
|
- `docs/database_domain_model_and_governance_v1_2026-03-27.md`
|
|||
|
|
- `docs/api_naming_strategy_supply_vs_supplier_v1_2026-03-27.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**文档状态**:设计稿(待评审)
|
|||
|
|
**下一步**:提交评审,根据反馈修订后进入实施阶段
|