Files
Edu/services/iam/docs/nextstep.md

290 lines
23 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.
# iam 下一步工作与上下游依赖Next Steps
> 模块iam身份与访问管理服务端口 3002 HTTP + 50052 gRPC
> 负责人ai06
> 更新日期2026-07-13
> 关联文档:
>
> - [iam_contract.md](../../docs/architecture/issues/contracts/iam_contract.md)
> - [iam_workline.md](../../docs/architecture/issues/worklines/iam_workline.md)
> - [02-architecture-design.md](./02-architecture-design.md)
---
## 1. 模块当前状态
iam 服务已完成 P2P6 全部批次,包含 15 个 gRPC RPC + 完整 REST CRUD + TOTP 2FA + 审计日志 + Outbox 事件发布 + Redis 权限缓存(含 Prometheus 指标)。本地 Docker 验证通过(真实 MySQL/Redis/Kafka无 mock 数据)。
### 1.1 本地 Docker 验证结果2026-07-13
测试环境:`edu-iam-test` 容器NODE_ENV=production, DEV_MODE=true接入 `edu-full_default` 网络,直连 edu-mysql / edu-redis / edu-kafka。
| 验证项 | 状态 | 说明 |
| ----------------------------------------------------------- | ---- | ------------------------------------------------------------------ |
| Docker 镜像构建 | ✅ | node:20-alpine + shared-ts 预编译 + pnpm install --frozen-lockfile |
| /healthz 健康检查 | ✅ | 200 `{"status":"ok","service":"iam"}` |
| /metrics Prometheus 指标 | ✅ | 含 iam_permission_cache_hits/misses/invalidations 三个新指标 |
| gRPC 50052 启动 | ✅ | 日志 `IAM service started (HTTP + gRPC dual entry)` |
| GET /.well-known/jwks.json | ✅ | 返回 RS256 公钥kid=iam-rs256-v1 |
| POST /v1/iam/register | ✅ | 创建用户 + 返回 JWT token 对 |
| POST /v1/iam/login | ✅ | 邮箱密码登录 + 返回 JWT token 对 |
| GET /v1/iam/me | ✅ | 返回当前用户信息 |
| PATCH /v1/iam/me | ✅ | 更新个人资料name/email |
| POST /v1/iam/change-password | ✅ | 密码强度校验 + 历史重用检查 + token 撤销 |
| GET /v1/iam/viewports | ✅ | 返回视口列表(含 level + componentConfig 字段) |
| GET /v1/iam/permissions/effective | ✅ | 返回用户有效权限列表 |
| GET /v1/iam/children | ✅ | 返回家长-学生关系 |
| GET /v1/iam/users分页 | ✅ | 返回用户列表 + total 总数 |
| PATCH /v1/iam/users/:id | ✅ | 管理员更新用户 |
| PATCH /v1/iam/users/:id/status | ✅ | 用户状态切换 |
| GET /v1/iam/roles | ✅ | 返回角色列表(含三层角色模型) |
| POST /v1/iam/roles | ✅ | 创建角色system/organization/temporary |
| PATCH /v1/iam/roles/:id | ✅ | 更新角色 |
| PATCH /v1/iam/roles/:id/permissions | ✅ | 批量更新角色权限 |
| POST/DELETE /v1/iam/roles/:roleId/permissions/:permissionId | ✅ | 单条授权/撤销 |
| GET /v1/iam/permissions | ✅ | 返回权限点列表 |
| POST /v1/iam/permissions | ✅ | 创建权限点 |
| PATCH /v1/iam/permissions/:id | ✅ | 更新权限点 |
| DELETE /v1/iam/permissions/:id | ✅ | 删除权限点(级联清理 role_permissions |
| POST /v1/iam/viewports | ✅ | 创建视口(含 level + componentConfig |
| PATCH /v1/iam/viewports/:id | ✅ | 更新视口 |
| DELETE /v1/iam/viewports/:id | ✅ | 删除视口 |
| POST /v1/iam/totp/enable | ✅ | 生成 TOTP 密钥 + QR URL + 10 个备份码 |
| POST /v1/iam/totp/verify | ✅ | 验证 TOTP 码pending → active |
| POST /v1/iam/totp/disable | ✅ | 禁用 TOTP |
| typecheck + lint | ✅ | 两项零错误 |
### 1.2 已完成的关键能力
| # | 能力 | 实现详情 |
| --- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | 15 个 gRPC RPC | Register/Login/RefreshToken/Logout/GetUserInfo/GetUserProfile/UpdateProfile/ChangePassword/BatchGetUsers/GetEffectivePermissions/GetEffectiveAccess/GetEffectiveDataScope/GetViewports/GetPublicKey/GetChildrenByParent |
| 2 | REST CRUD 完整 | 角色/权限/视口/用户/TOTP 全部 CRUD 端点 |
| 3 | 三层角色模型 | systemlevel=0/ organizationlevel=1/ temporarylevel=2 |
| 4 | DataScope 6 级 | self/subject/class/grade/school/all |
| 5 | 视口 4 层 + L4 数据级配置 | admin/teacher/student/parent + componentConfig JSON |
| 6 | 密码策略 | bcrypt cost 12 + 强度校验 + 5 次历史重用限制 |
| 7 | TOTP 2FA | RFC 6238 HMAC-SHA1 纯 JS 实现 + 10 备份码 |
| 8 | 审计日志 | ip/userAgent/traceId 从请求头提取 + Outbox 事件发布 |
| 9 | JWKS 端点 | `GET /v1/iam/.well-known/jwks.json` 暴露 RS256 公钥 |
| 10 | Redis 权限缓存 | TTL 5min + 角色变更失效 + hit/miss/invalidation 指标 |
| 11 | Outbox 模式 | iam_outbox 表 + Kafka publisheredu.iam.user.events / edu.iam.role.events / edu.iam.audit.created |
| 12 | AuthMiddleware | 从 Gateway 注入的 x-user-* 头部解析用户身份 |
| 13 | PermissionGuard | APP_GUARD + DB 驱动 + Redis 缓存 + dataScope=all 跳过校验 |
---
## 2. 上游依赖iam 依赖谁)
iam 作为身份基础设施服务,运行时依赖以下组件:
### 2.1 MySQL基础设施— P0
| 项 | 内容 |
| -------- | ----------------------------------------------------------------- |
| 依赖内容 | 用户/角色/权限/视口/审计日志/密码历史/TOTP/Outbox 表 |
| 端点 | `mysql://edu:changeme@edu-mysql:3306/next_edu_cloud` |
| 用途 | 所有业务数据持久化 |
| 当前状态 | ✅ 本地 Docker edu-mysql 已就绪 |
| 环境变量 | `DATABASE_URL=mysql://edu:changeme@edu-mysql:3306/next_edu_cloud` |
### 2.2 Redis基础设施— P0
| 项 | 内容 |
| -------- | ---------------------------------------------- |
| 依赖内容 | 权限缓存 + token 黑名单 |
| 端点 | `redis://edu-redis:6379` |
| 用途 | 1) 用户权限缓存TTL 5min2) 角色变更失效广播 |
| 当前状态 | ✅ 本地 Docker edu-redis 已就绪 |
| 环境变量 | `REDIS_URL=redis://edu-redis:6379` |
### 2.3 Kafka基础设施— P1
| 项 | 内容 |
| -------- | ------------------------------------------------------------------------------------ |
| 依赖内容 | Outbox 事件投递edu.iam.user.events / edu.iam.role.events / edu.iam.audit.created |
| 端点 | `kafka:29092`(容器内 INSIDE listener |
| 用途 | 事务性事件发布(用户注册/登录/角色变更/审计日志) |
| 当前状态 | ✅ 本地 Docker edu-kafka 已就绪 |
| 环境变量 | `KAFKA_BROKERS=kafka:29092``KAFKA_CLIENT_ID=iam-service` |
| 降级策略 | Kafka 不可用时 Outbox 表持续累积Kafka 恢复后自动投递 |
### 2.4 shared-proto协调 AI 维护)— P0
| 项 | 内容 |
| -------- | ------------------------------------------------ |
| 依赖内容 | `packages/shared-proto/proto/iam.proto` 契约定义 |
| 用途 | gRPC 服务定义 + proto-loader 运行时加载 |
| 当前状态 | ✅ 15 个 RPC 全部声明 |
### 2.5 shared-ts协调 AI 维护)— P0
| 项 | 内容 |
| -------- | ---------------------------------------------------- |
| 依赖内容 | `@edu/shared-ts/outbox` OutboxModule + OutboxService |
| 用途 | 事务性事件发布框架 |
| 当前状态 | ✅ 已构建并集成 |
---
## 3. 下游依赖(谁依赖 iam
以下 9 个模块依赖 iam 服务:
### 3.1 api-gatewayai01 负责)— P0
| # | 依赖项 | 用途 | 状态 |
| --- | ----------------------------------- | ---------------------------------------------------- | --------- |
| 1 | `GET /v1/iam/.well-known/jwks.json` | RS256 公钥集JWKSTTL 5min 缓存 | ✅ 已就绪 |
| 2 | RS256 JWT 签发 | api-gateway 用 JWKS 公钥校验 access_token | ✅ 已就绪 |
| 3 | `GET /healthz` 端点 | /readyz 下游健康检查 | ✅ 已就绪 |
| 4 | JWT claims 含 role/data_scope | api-gateway 注入 x-user-roles / x-user-data-scope 头 | ✅ 已就绪 |
**验证结果**JWKS 端点返回有效公钥JWT token 可被 RS256 验签。
### 3.2 push-gatewayai09 负责)— P0
| # | 依赖项 | 用途 | 状态 |
| --- | ---------------------------------------- | ----------------------------------------- | --------- |
| 1 | `GET /v1/iam/.well-known/jwks.json` | WebSocket `/ws` 连接时校验客户端 JWT 签名 | ✅ 已就绪 |
| 2 | shared-go/jwks Fetcher 每 5 分钟刷新缓存 | JWKS 缓存刷新 | ✅ 已就绪 |
**环境变量**`JWKS_URL=http://iam:3002/v1/iam/.well-known/jwks.json`
### 3.3 teacher-bffai03 负责)— P0
| # | 依赖项 | 用途 | 状态 |
| --- | ------------------------------------------------ | ----------------------------- | --------- |
| 1 | gRPC `GetUserInfo(userId)` :50052 | `currentUser`/`me` 查询 | ✅ 已就绪 |
| 2 | gRPC `BatchGetUsers(userIds)` :50052 | `adminUsers` 查询 | ✅ 已就绪 |
| 3 | gRPC `GetEffectivePermissions(userId)` :50052 | 用户有效权限列表 | ✅ 已就绪 |
| 4 | gRPC `GetEffectiveDataScope(userId)` :50052 | 用户数据范围 | ✅ 已就绪 |
| 5 | gRPC `GetViewports(userId)` :50052 | `adminViewports` 查询 | ✅ 已就绪 |
| 6 | gRPC `GetPublicKey()` :50052 | RS256 公钥 | ✅ 已就绪 |
| 7 | gRPC `GetChildrenByParent(parentId)` :50052 | 家长端学生列表 | ✅ 已就绪 |
| 8 | REST `GET /v1/iam/roles` :3002 | `adminRoles` 查询 | ✅ 已就绪 |
| 9 | REST `GET /v1/iam/permissions` :3002 | `adminPermissions` 查询 | ✅ 已就绪 |
| 10 | REST `GET /v1/iam/audit` :3002 | `auditLogs` 查询 | ✅ 已就绪 |
| 11 | REST `GET /v1/iam/viewports` :3002 | `adminViewports` 查询(备选) | ✅ 已就绪 |
| 12 | REST `GET /v1/iam/permissions/effective` :3002 | 用户有效权限(备选) | ✅ 已就绪 |
| 13 | `GET /.well-known/jwks.json` :3002 | RS256 JWKS | ✅ 已就绪 |
| 14 | `POST /v1/iam/register` / `POST /v1/iam/login` | 用户注册/登录 | ✅ 已就绪 |
| 15 | `PATCH /v1/iam/users/:id` | 用户更新 | ✅ 已就绪 |
| 16 | `POST /v1/iam/roles` / `PATCH /v1/iam/roles/:id` | 角色创建/更新 | ✅ 已就绪 |
**环境变量**`IAM_GRPC_TARGET=iam:50052``IAM_SERVICE_URL=http://iam:3002`
### 3.4 student-bffai04 负责)— P0
| # | gRPC 方法 | 用途 | 状态 |
| --- | ---------------- | ------------------------- | --------- |
| 1 | `GetUserProfile` | `myProfile` Query | ✅ 已就绪 |
| 2 | `UpdateProfile` | `updateProfile` Mutation | ✅ 已就绪 |
| 3 | `ChangePassword` | `changePassword` Mutation | ✅ 已就绪 |
**proto 位置**`packages/shared-proto/proto/iam.proto`
### 3.5 parent-bffai05 负责)— P0
| # | RPC 方法 | 用途 | 状态 |
| --- | --------------------------------- | ---------------------- | --------- |
| 1 | `getUserInfo(userId)` | 获取家长个人信息 | ✅ 已就绪 |
| 2 | `getChildrenByParent(parentId)` | 获取家长绑定的孩子列表 | ✅ 已就绪 |
| 3 | `getViewports(userId)` | 获取家长可见视口 | ✅ 已就绪 |
| 4 | `getEffectivePermissions(userId)` | 获取家长有效权限 | ✅ 已就绪 |
| 5 | `GET /healthz` 端点 | /readyz 下游健康检查 | ✅ 已就绪 |
| 6 | `GET /.well-known/jwks.json` | RS256 公钥集 | ✅ 已就绪 |
**环境变量**`IAM_GRPC_TARGET=iam:50052`
### 3.6 teacher-portalai13 负责)— P1
| # | 依赖项 | 用途 | 状态 |
| --- | ----------------------------------- | ------------------------------------------ | --------- |
| 1 | JWT RS256 签发 | 登录后获取 access_token + refresh_token | ✅ 已就绪 |
| 2 | `POST /v1/iam/login` | 教师登录 | ✅ 已就绪 |
| 3 | `POST /v1/iam/refresh` | 刷新 token | ✅ 已就绪 |
| 4 | `POST /v1/iam/logout` | 登出 | ✅ 已就绪 |
| 5 | `GET /v1/iam/me` | 获取当前用户信息 | ✅ 已就绪 |
| 6 | `GET /v1/iam/viewports` | 获取视口配置(含 level + componentConfig | ✅ 已就绪 |
| 7 | `GET /v1/iam/permissions/effective` | 获取有效权限 | ✅ 已就绪 |
### 3.7 student-portalai14 负责)— P1
| # | 依赖项 | 用途 | 状态 |
| --- | ------------------------------ | ------------ | --------- |
| 1 | JWT RS256 签发 | 学生登录 | ✅ 已就绪 |
| 2 | `POST /v1/iam/login` | 学生登录 | ✅ 已就绪 |
| 3 | `PATCH /v1/iam/me` | 更新个人资料 | ✅ 已就绪 |
| 4 | `POST /v1/iam/change-password` | 修改密码 | ✅ 已就绪 |
### 3.8 parent-portalai15 负责)— P1
| # | 依赖项 | 用途 | 状态 |
| --- | ---------------------- | ------------------ | --------- |
| 1 | JWT RS256 签发 | 家长登录 | ✅ 已就绪 |
| 2 | `POST /v1/iam/login` | 家长登录 | ✅ 已就绪 |
| 3 | `GET /v1/iam/children` | 获取绑定的学生列表 | ✅ 已就绪 |
| 4 | `GET /v1/iam/me` | 获取家长个人信息 | ✅ 已就绪 |
### 3.9 admin-portalai16 负责)— P0
| # | 依赖项 | 用途 | 状态 |
| --- | ------------------------------------------------- | --------------------------- | --------- |
| 1 | `GET /v1/iam/users` | 用户管理列表(分页 + 搜索) | ✅ 已就绪 |
| 2 | `PATCH /v1/iam/users/:id` | 用户更新 | ✅ 已就绪 |
| 3 | `PATCH /v1/iam/users/:id/status` | 用户状态切换 | ✅ 已就绪 |
| 4 | `POST/PATCH/DELETE /v1/iam/roles` | 角色 CRUD | ✅ 已就绪 |
| 5 | `POST/PATCH/DELETE /v1/iam/permissions` | 权限 CRUD | ✅ 已就绪 |
| 6 | `POST/PATCH/DELETE /v1/iam/viewports` | 视口 CRUD | ✅ 已就绪 |
| 7 | `POST /v1/iam/totp/enable` / `verify` / `disable` | TOTP 2FA 管理 | ✅ 已就绪 |
| 8 | `GET /v1/iam/audit` | 审计日志查询 | ✅ 已就绪 |
---
## 4. 剩余工作
### 4.1 已完成
| 工作项 | 状态 |
| ----------------------- | ---- |
| P2-P6 全部批次 | ✅ |
| 15 个 gRPC RPC | ✅ |
| REST CRUD 完整 | ✅ |
| TOTP 2FA | ✅ |
| 密码策略 + 历史重用 | ✅ |
| 审计日志 + Outbox | ✅ |
| Redis 权限缓存 + 指标 | ✅ |
| JWKS 端点 | ✅ |
| Docker 本地测试通过 | ✅ |
| typecheck + lint 零错误 | ✅ |
### 4.2 待办(非阻塞)
| # | 工作项 | 优先级 | 阻塞条件 |
| --- | --------------------------------------------------------------------------- | ------ | ------------ |
| 1 | 单元测试 + 集成测试覆盖率 ≥ 80% | P2 | 无 |
| 2 | 生产环境 JWT 密钥轮换流程 | P3 | 生产部署前 |
| 3 | Kafka topic 创建自动化edu.iam.user.events / role.events / audit.created | P3 | K8s 部署阶段 |
| 4 | 数据库迁移脚本drizzle-kit | P3 | 生产部署前 |
---
## 5. 联调待办
| # | 联调项 | 对端模块 | 状态 |
| --- | ------------------------------------------------------- | --------------------- | --------- |
| 1 | api-gateway JWKS 真实验签 | api-gateway (ai01) | ✅ 已就绪 |
| 2 | push-gateway JWKS 真实验签 | push-gateway (ai09) | ✅ 已就绪 |
| 3 | teacher-bff gRPC 全量调用 | teacher-bff (ai03) | ✅ 已就绪 |
| 4 | student-bff GetUserProfile/UpdateProfile/ChangePassword | student-bff (ai04) | ✅ 已就绪 |
| 5 | parent-bff getUserInfo/getChildrenByParent/getViewports | parent-bff (ai05) | ✅ 已就绪 |
| 6 | admin-portal RBAC CRUD 全量 | admin-portal (ai16) | ✅ 已就绪 |
| 7 | teacher-portal 登录 + 视口 | teacher-portal (ai13) | ✅ 已就绪 |
| 8 | student-portal 登录 + 个人资料 | student-portal (ai14) | ✅ 已就绪 |
| 9 | parent-portal 登录 + 孩子列表 | parent-portal (ai15) | ✅ 已就绪 |
---
**本文件由 ai06 维护。iam 服务已全量就绪,所有下游模块可开始真实联调。**