docs: add Phase 1 IAM and authorization implementation plan

Define the database, PostgresAuthStore, AuthorizationService, and frontend
capabilities workstream after Phase 0 security止血 is complete.
This commit is contained in:
weichen
2026-09-12 01:01:20 +00:00
parent 8341168271
commit 77d3da116f
@@ -0,0 +1,99 @@
# Phase 1:账户与授权权威化 Implementation Plan
> **依据**:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) §5.2、§4、§12、Phase 1
> **前置**:Phase 0 已合并(5 commits on `dev`,`8341168`)
**Goal:** 登录、角色、权限、项目成员关系全部以数据库 + 服务端策略为唯一权威;前端只消费 `capabilities`;重启后会话/账户策略仍有效;禁用账户下一请求失效。
**Architecture:** Goose 迁移新增 IAM 表 → `PostgresAuthStore` 替换 `MemoryStore`(dev 可 feature flag 回退)→ `AuthorizationService` 统一 RBAC + `project_members` + admin 判定 → `/api/v1/auth/me` 返回 capabilities → 管理端用户/角色 API 持久化 → 前端移除 localStorage 权限权威。
**Tech Stack:** Goose、pgx、现有 `internal/auth`、`internal/authz`、React/Vite。
**明确不在本阶段:** 工作流版本模型、阶段 ABAC、capabilities 到每个 DocGov 动作的全覆盖(先系统 + 项目 + 已挂 authz 路由)。
---
## 完成门禁
| 门禁 | 判定 |
|---|---|
| 持久化账户 | 重启后 users/roles 仍在 DB |
| 持久化会话 | token 存哈希;logout/禁用立即失效 |
| 无 localStorage RBAC 权威 | `AdminSettingsModal` 读写 API;`hasPermission` 仅 UI 兜底并标注 deprecated |
| 项目成员 CRUD | 创建者可增删改成员;API 测试 |
| 负例 | 禁用用户 token → 401;跨项目已挂 authz → 403 |
---
## 任务分解
### Task 1 — IAM 数据库迁移(`feat(db)`)
新建 `deploy/postgres/goose/00015_iam_core.sql`:
- `users`(id, username, display_name, email, status, department, employee_id, locale, timezone, created_at, updated_at)
- `user_credentials`(user_id, password_hash, password_changed_at, failed_count, locked_until)
- `auth_sessions`(id, token_hash, user_id, created_at, last_seen_at, idle_expires_at, absolute_expires_at, revoked_at, ip_hash, user_agent)
- `roles` / `permissions` / `role_permissions` / `user_role_bindings`
- seed:`role-admin` + 核心 permissions + 从 MemoryStore dev 用户回填(仅 dev/test 迁移脚本)
约束:username unique;token_hash unique;至少一个 super-admin binding。
### Task 2 — PostgresAuthStore(`feat(auth)`)
- `internal/auth/pg_store.go` 实现 `AuthStore`
- 会话:Login 写 `auth_sessions`(只存 SHA256(token));ValidateToken 查库 + 更新 last_seen
- Logout/RevokeAll 标记 revoked_at
- `server.go`:有 `ContextDbHost` 时用 PgStore,否则 dev 仍 MemoryStore
### Task 3 — AuthorizationService(`feat(authz)`)
- `internal/authz/service.go`:`Capabilities(ctx, userID) []string`
- `HasPermission(ctx, userID, perm, scope)` 组合系统 role_bindings + `project_members`
- 替换 scattered `role-admin` 硬编码 → `HasSystemPermission(..., "system.admin")` 或保留 admin role_id 映射
- `requireAdmin` / `requireProjectAccess` 改调用 Authorizer + AuthzService
### Task 4 — Auth API 扩展(`feat(api)`)
- `GET /api/v1/auth/me` 增加 `capabilities: string[]`
- 会话列表/撤销(用户设置 Phase 1 最小版):`GET/DELETE /api/v1/auth/sessions`
- Admin users/roles CRUD 对齐 DB(现有 handler 改接 PgStore)
### Task 5 — 项目成员 API(`feat(api)`)
- `GET/POST/PUT/DELETE /api/v1/projects/{id}/members`
- 仅 owner/creator + `projects.members.manage` 可写
- 与 `project_members` 表对齐;禁止把 author/reviewer/approver 写入成员 role
### Task 6 — 前端 capabilities(`feat(web)`)
- `authClient.me()` 缓存 capabilities
- `engine/rbac.ts`:`hasPermission` 优先读 capabilities;localStorage roles 只读迁移提示
- `AdminSettingsModal` / `UserProjectRightsModal` 成员编辑走 API
- 移除 `loadRoles(DEFAULT_ROLES)` 作为权威初始化(保留 demo 数据只读展示直至导入完成)
### Task 7 — 测试与报告(`test` / `docs(test)`)
- `internal/auth/pg_store_test.go`(testcontainers 或 stub pg)
- `internal/authz/service_test.go`
- 扩展 `security_p0_test` + 跨项目 403(需 DB fixture)
- `.doc/test-reports/2026-09-12-phase1-iam-authz-test-report.md`
---
## 建议提交节奏
1. `feat(db):` IAM goose migration + seed
2. `feat(auth):` PostgresAuthStore + session persistence
3. `feat(authz):` AuthorizationService + admin gate
4. `feat(api):` members CRUD + auth/me capabilities
5. `feat(web):` frontend capabilities consumer
6. `test(docs):` Phase 1 report
---
## 风险
- **双写期**:MemoryStore 与 PG 并存时须单一 Store 注入,避免混用。
- **ID 对齐**:现有 `projects.creator_user_id` / memory user id 与 PG users.id 迁移需一次性回填脚本。
- **前端降级**:capabilities 未加载前 fail closed(禁用敏感按钮,不默认 allow)。