Files
iam-service/docs/SCALAR_GUIDE.md
2026-01-31 17:23:56 +08:00

14 KiB
Raw Blame History

IAM Service — Scalar 调用顺序指南v0.1.0

Authentication认证方式

本服务使用 JWT Bearer Token

  • 登录成功后拿到 access_token
  • 后续请求在 Header 中带:
    • Authorization: Bearer <access_token>
  • 租户上下文:
    • 保护接口默认从 Token claim 的 tenant_id 推导租户
    • 可选兼容 X-Tenant-ID: <uuid>,若同时提供 Header 与 Token则必须一致否则返回 403

访问令牌JWTtenant_id/user_id/roles/permissions 外,还包含:

  • apps:租户已开通应用列表(如 ["cms","tms"]
  • apps_version:租户 enabled_apps 版本号(用于客户端判断是否需要刷新会话)

OpenAPI/Scalar 可配置参数(环境变量)

为方便本地调试与演示,服务会在生成 OpenAPI 文档时,将部分 Header 参数的示例值按环境变量动态注入(影响 /scalar 展示,不影响服务鉴权逻辑):

  • IAM_DOCS_DEFAULT_TENANT_ID:默认租户 ID用于 X-Tenant-ID Header 的 example
    • 未设置时默认:11111111-1111-1111-1111-111111111111
    • 可选强制:IAM_DOCS_REQUIRE_TENANT_ID=1(未设置则启动时直接失败)
  • IAM_DOCS_DEFAULT_TOKEN:默认 Token用于 Authorization Header 的 example
    • 可填写裸 JWT 或 Bearer <jwt>;裸 JWT 会自动补齐 Bearer
    • 未设置时默认:Bearer <access_token>
    • 可选强制:IAM_DOCS_REQUIRE_TOKEN=1(未设置则启动时直接失败)

通用响应结构

成功响应:

{ "code": 0, "message": "Success|Created|Accepted", "data": {}, "trace_id": null }

错误响应(示例):

{ "code": 20006, "message": "Missing authorization header", "details": null, "trace_id": null }

常见错误码(节选):

  • 20006缺少必要 Header如 Authorization
  • 20003无权限403
  • 20005账号或密码错误
  • 30000请求参数错误400
  • 30002资源不存在404
  • 30003资源冲突409
  • 40000请求过于频繁429
  • 10001数据库错误500

Step-by-step可复制流程

Step -1数据库初始化 / 迁移(开发/测试/生产)

本服务新增了“租户已开通应用enabled_apps”与“平台超级管理员SuperAdmin”能力对应数据库新增表

  • apps
  • tenant_entitlements
  • tenant_enabled_apps_history

推荐使用版本化迁移脚本初始化与升级:

  • 执行迁移:scripts/db/migrate.sh
  • 执行校验:scripts/db/verify.sh
  • 回滚(按版本):scripts/db/rollback.sh

本仓库同时保留开发用的一键重建脚本:scripts/db/rebuild_iam_db.sh(会清库重建,不适合生产)。

Step 0创建租户可选

POST /tenants/register

  • TagTenant
  • Header
  • 二次验证(可选但建议生产启用):
    • 若设置环境变量 IAM_SENSITIVE_ACTION_TOKEN,则必须传 HeaderX-Sensitive-Token: <token>,否则返回 403。
  • Body
{ "name": "Tenant A", "config": { "theme": { "primary": "#1d4ed8" } } }

成功201data.id 取出租户 ID

{ "code": 0, "message": "Created", "data": { "id": "<tenant_id>", "name": "Tenant A", "status": "active", "config": {} }, "trace_id": null }

下一步依赖:tenant_id(用于注册/登录时的 X-Tenant-ID)。

Step 0.1:平台超级管理员(可选,但推荐先完成)

数据库已内置平台租户Platform tenant

  • tenant_id = 00000000-0000-0000-0000-000000000001

在平台租户下注册首个用户,将自动获得平台级权限(用于管理各租户 enabled_apps

POST /auth/register

  • TagAuth
  • HeaderX-Tenant-ID: 00000000-0000-0000-0000-000000000001
  • Body
{ "email": "superadmin@example.com", "password": "securePassword123" }

Step 1注册用户

POST /auth/register

  • TagAuth
  • 必需 HeaderX-Tenant-ID: <tenant_id>
  • Body
{ "email": "user@example.com", "password": "securePassword123" }

成功201data.id 取出 user_id(后续可用于用户管理接口):

{ "code": 0, "message": "Created", "data": { "id": "<user_id>", "email": "user@example.com" }, "trace_id": null }

Step 2登录获取访问令牌Authentication 入口)

POST /auth/login

  • TagAuth
  • 必需 HeaderX-Tenant-ID: <tenant_id>
  • Body
{ "email": "user@example.com", "password": "securePassword123" }

成功200data.access_token 取出访问令牌:

{ "code": 0, "message": "Success", "data": { "access_token": "<jwt>", "refresh_token": "<opaque>", "token_type": "Bearer", "expires_in": 900 }, "trace_id": null }

下一步依赖:access_token

(可选)使用 refresh_token 自动续期:

  • POST /auth/refresh
  • TagAuth
  • Header
  • Body
{ "refresh_token": "<opaque>" }

Step 3获取当前租户信息Tenant

GET /tenants/me

  • TagTenant
  • 必需 HeaderAuthorization: Bearer <access_token>
  • 可选 HeaderX-Tenant-ID: <tenant_id>(如提供必须与 token tenant_id 一致)

成功200

{ "code": 0, "message": "Success", "data": { "id": "<tenant_id>", "name": "Tenant A", "status": "active", "config": {} }, "trace_id": null }

Step 4查看当前用户权限Me

GET /me/permissions

  • TagMe
  • 必需 HeaderAuthorization: Bearer <access_token>

成功200

{ "code": 0, "message": "Success", "data": ["tenant:read","tenant:write"], "trace_id": null }

下一步依赖:确认具备目标权限(例如 user:read / role:read)。

Step 4.1平台层设置租户已开通应用SuperAdmin

该能力仅允许拥有平台级权限的用户调用:

  • iam:tenant:enabled_apps:read
  • iam:tenant:enabled_apps:write

4.1.1 查询某租户 enabled_apps

GET /platform/tenants/{tenant_id}/enabled-apps

  • TagTenant
  • HeaderAuthorization: Bearer <access_token>(平台租户下登录得到的 token

4.1.2 设置某租户 enabled_apps全量覆盖幂等

PUT /platform/tenants/{tenant_id}/enabled-apps

  • TagTenant
  • HeaderAuthorization: Bearer <access_token>
  • Body
{ "enabled_apps": ["cms", "tms"], "expected_version": 0 }

说明:

  • expected_version 可选,用于并发控制;不匹配会返回 409。
  • 登录签发 token 时会自动把 apps/apps_version 注入到 JWT并对 permissions 按 enabled_apps 过滤。
  • enabled_apps 必须是“应用注册表 apps 表”中存在且 status=active 的应用 ID若传入未知/已下线应用(例如 dms),接口会返回 400。

enabled_apps 维护建议:

  • 新增应用:通过数据库迁移向 apps(id,name,description,status) 插入一行(id 推荐全小写短标识,如 cms / tms)。
  • 下线应用:将 apps.status 置为非 active(例如 disabled),之后将无法再被设置进任何租户的 enabled_apps。
  • 查询可用应用(示例 SQLSELECT id, name, status FROM apps ORDER BY id;

Step 4.2:平台层 App 生命周期管理SuperAdmin

用于维护“允许的 App 注册表”,并提供应用上下线(审批 + 生效时间)能力。

权限要求(平台级):

  • iam:app:read
  • iam:app:write
  • iam:app:approve
  • iam:app:delete

4.2.1 新增 App

POST /platform/apps

  • TagApp
  • HeaderAuthorization: Bearer <access_token>(平台租户下登录得到的 token
  • Body示例
{ "id": "dms", "name": "DMS", "description": "Document Management System", "app_type": "product", "owner": "team-a" }

4.2.2 查询 App 列表(分页/筛选/排序)

GET /platform/apps?page=1&page_size=20&status=active&app_type=product&sort_by=created_at&sort_order=desc

  • TagApp
  • HeaderAuthorization: Bearer <access_token>

4.2.3 更新 App 基础信息

PATCH /platform/apps/{app_id}

  • TagApp
  • HeaderAuthorization: Bearer <access_token>
  • Body示例
{ "description": "DMS v2", "owner": "team-b" }

4.2.4 申请 App 上下线(需要审批,可设置生效时间)

POST /platform/apps/{app_id}/status-change-requests

  • TagApp
  • HeaderAuthorization: Bearer <access_token>
  • Body示例立即禁用
{ "to_status": "disabled", "reason": "security patch" }
  • Body示例延迟生效
{ "to_status": "disabled", "effective_at": "2026-02-01T00:00:00Z", "reason": "maintenance window" }

4.2.5 审批上下线申请单

GET /platform/app-status-change-requests?status=pending&page=1&page_size=20

POST /platform/app-status-change-requests/{request_id}/approve

POST /platform/app-status-change-requests/{request_id}/reject?reason=...

4.2.6 删除 App软删除

DELETE /platform/apps/{app_id}

  • TagApp
  • HeaderAuthorization: Bearer <access_token>
  • 二次验证(可选但建议生产启用):
    • 若设置环境变量 IAM_SENSITIVE_ACTION_TOKEN,则必须同时传 HeaderX-Sensitive-Token: <token>,否则返回 403。

Step 5列出用户User

GET /users?page=1&page_size=20

  • TagUser
  • 必需 HeaderAuthorization: Bearer <access_token>
  • 分页规则:
    • page 默认 1必须 >= 1
    • page_size 默认 20范围 1..=200

成功200

{ "code": 0, "message": "Success", "data": [{ "id": "<user_id>", "email": "user@example.com" }], "trace_id": null }

Step 6列出角色Role

GET /roles

  • TagRole
  • 必需 HeaderAuthorization: Bearer <access_token>

成功200

{ "code": 0, "message": "Success", "data": [{ "id": "<role_id>", "name": "Admin", "description": "..." }], "trace_id": null }

Role & Permission Management

本节补齐“角色Role与权限Permission管理”的完整指引适用于横向扩展到多个应用cms / tms / iam 等)。

权限模型(可扩展到十几个应用)

权限编码规范:

  • permission.code 统一采用:${app_code}:${resource}:${action}
    • 示例:cms:article:publishtms:task:assigniam:tenant:enabled_apps:write
  • app_code 必须与应用注册表app_registry中的应用标识一致本项目对应表为 apps.id)。
  • 支持通配符(需要在 permissions.code 中显式存储通配符权限并分配到角色):
    • cms:*:*CMS 全权限
    • cms:article:*:文章相关全权限

说明:鉴权时支持通配符匹配(例如持有 cms:article:* 可满足 cms:article:publish),但只有当该通配符权限被写入 permissions 并绑定到角色时才会生效。

数据库关系ER 图):

erDiagram
  apps {
    VARCHAR id PK
    VARCHAR name
    VARCHAR status
  }
  permissions {
    UUID id PK
    VARCHAR code
    TEXT description
    VARCHAR resource
    VARCHAR action
  }
  users {
    UUID id PK
    UUID tenant_id FK
    VARCHAR email
  }
  roles {
    UUID id PK
    UUID tenant_id FK
    VARCHAR name
    BOOLEAN is_system
  }
  role_permissions {
    UUID role_id FK
    UUID permission_id FK
  }
  user_roles {
    UUID user_id FK
    UUID role_id FK
  }

  apps ||--o{ permissions : namespaces
  roles ||--o{ role_permissions : grants
  permissions ||--o{ role_permissions : assigned
  users ||--o{ user_roles : has
  roles ||--o{ user_roles : assigned

应用区分方式:

  • 通过 appsapp_registry维护“允许的应用标识”并要求权限码的 app_codeapps.id 一致。
  • 在租户侧通过 enabled_apps 控制某租户开通哪些应用;登录/权限查询会按 enabled_apps 过滤应用级权限(例如 cms:*:* 会在租户未开通 cms 时被过滤)。

1) 为 CMS 添加最小必要权限SQL

脚本位置:scripts/db/migrations/0006_cms_permissions.sql

包含权限项:

  • 文章:创建、编辑、发布
  • 栏目:管理
  • 媒体库:管理
  • 系统配置:管理

2) 查询权限列表(分页/搜索)

GET /permissions?page=1&page_size=20&app_code=cms&search=article

  • TagPermission
  • HeaderAuthorization: Bearer <access_token>
  • 需要权限:role:read

3) 角色 CRUDRole

创建角色:

  • POST /roles

查询角色详情:

  • GET /roles/{id}

更新角色:

  • PATCH /roles/{id}

删除角色:

  • DELETE /roles/{id}

说明:

  • 系统内置角色(is_system=true,如 Admin)不允许通过 API 修改/删除。

4) 为角色批量绑定/解绑权限

绑定权限(批量):

  • POST /roles/{id}/permissions/grant
  • Body
{ "permission_codes": ["cms:article:create", "cms:article:publish"] }

解绑权限(批量):

  • POST /roles/{id}/permissions/revoke

5) 批量给用户授予/回收角色

批量授予:

  • POST /roles/{id}/users/grant
  • Body
{ "user_ids": ["<user_id_1>", "<user_id_2>"] }

批量回收:

  • POST /roles/{id}/users/revoke

审计说明:

  • 角色创建/更新/删除、角色-权限绑定/解绑、角色-用户授予/回收都会写入 audit_logs

Step 7用户-角色绑定User

用户注册后默认无角色;通常由具备 user:write 的管理员进行角色分配。

7.1 查询用户角色列表(需要 user:read

GET /users/{id}/roles

  • TagUser
  • HeaderAuthorization: Bearer <access_token>

7.2 设置用户角色(全量覆盖,幂等;需要 user:write

PUT /users/{id}/roles

  • TagUser
  • HeaderAuthorization: Bearer <access_token>
  • Body
{ "role_ids": ["<role_id_1>", "<role_id_2>"] }

说明:

  • role_ids 必须全部属于当前租户,否则返回 400。

限流说明Auth

  • /auth/login:约 2 req/sburst 10同一 IP
  • /auth/register:约 1 req/sburst 5同一 IP
  • 触发后返回HTTP 429 + code=40000

密码重置User

用户自助重置(需要旧密码):

  • POST /users/me/password/reset
  • TagUser
  • HeaderAuthorization: Bearer <access_token>
  • Body
{ "current_password": "oldPassword123", "new_password": "newPassword456" }

租户管理员重置任意用户(生成临时密码):

  • POST /users/{id}/password/reset
  • TagUser
  • HeaderAuthorization: Bearer <access_token>
  • 权限:需要 user:password:reset:any
  • 二次验证(可选但建议生产启用):
    • 若设置环境变量 IAM_SENSITIVE_ACTION_TOKEN,则必须传 HeaderX-Sensitive-Token: <token>,否则返回 403。