Files
lijiaoqiao/docs/multi_role_permission_design_v1_2026-04-02.md
Your Name 89104bd0db feat(P1/P2): 完成TDD开发及P1/P2设计文档
## 设计文档
- multi_role_permission_design: 多角色权限设计 (CONDITIONAL GO)
- audit_log_enhancement_design: 审计日志增强 (CONDITIONAL GO)
- routing_strategy_template_design: 路由策略模板 (CONDITIONAL GO)
- sso_saml_technical_research: SSO/SAML调研 (CONDITIONAL GO)
- compliance_capability_package_design: 合规能力包设计 (CONDITIONAL GO)

## TDD开发成果
- IAM模块: supply-api/internal/iam/ (111个测试)
- 审计日志模块: supply-api/internal/audit/ (40+测试)
- 路由策略模块: gateway/internal/router/ (33+测试)
- 合规能力包: gateway/internal/compliance/ + scripts/ci/compliance/

## 规范文档
- parallel_agent_output_quality_standards: 并行Agent产出质量规范
- project_experience_summary: 项目经验总结 (v2)
- 2026-04-02-p1-p2-tdd-execution-plan: TDD执行计划

## 评审报告
- 5个CONDITIONAL GO设计文档评审报告
- fix_verification_report: 修复验证报告
- full_verification_report: 全面质量验证报告
- tdd_module_quality_verification: TDD模块质量验证
- tdd_execution_summary: TDD执行总结

依据: Superpowers执行框架 + TDD规范
2026-04-02 23:35:53 +08:00

698 lines
26 KiB
Markdown
Raw 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.
# 多角色权限设计方案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`
---
**文档状态**:设计稿(待评审)
**下一步**:提交评审,根据反馈修订后进入实施阶段