290 lines
23 KiB
Markdown
290 lines
23 KiB
Markdown
# 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 服务已完成 P2–P6 全部批次,包含 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 | 三层角色模型 | system(level=0)/ organization(level=1)/ temporary(level=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 publisher(edu.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 5min)2) 角色变更失效广播 |
|
||
| 当前状态 | ✅ 本地 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-gateway(ai01 负责)— P0
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | ----------------------------------- | ---------------------------------------------------- | --------- |
|
||
| 1 | `GET /v1/iam/.well-known/jwks.json` | RS256 公钥集(JWKS),TTL 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-gateway(ai09 负责)— 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-bff(ai03 负责)— 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-bff(ai04 负责)— P0
|
||
|
||
| # | gRPC 方法 | 用途 | 状态 |
|
||
| --- | ---------------- | ------------------------- | --------- |
|
||
| 1 | `GetUserProfile` | `myProfile` Query | ✅ 已就绪 |
|
||
| 2 | `UpdateProfile` | `updateProfile` Mutation | ✅ 已就绪 |
|
||
| 3 | `ChangePassword` | `changePassword` Mutation | ✅ 已就绪 |
|
||
|
||
**proto 位置**:`packages/shared-proto/proto/iam.proto`
|
||
|
||
### 3.5 parent-bff(ai05 负责)— 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-portal(ai13 负责)— 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-portal(ai14 负责)— P1
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | ------------------------------ | ------------ | --------- |
|
||
| 1 | JWT RS256 签发 | 学生登录 | ✅ 已就绪 |
|
||
| 2 | `POST /v1/iam/login` | 学生登录 | ✅ 已就绪 |
|
||
| 3 | `PATCH /v1/iam/me` | 更新个人资料 | ✅ 已就绪 |
|
||
| 4 | `POST /v1/iam/change-password` | 修改密码 | ✅ 已就绪 |
|
||
|
||
### 3.8 parent-portal(ai15 负责)— P1
|
||
|
||
| # | 依赖项 | 用途 | 状态 |
|
||
| --- | ---------------------- | ------------------ | --------- |
|
||
| 1 | JWT RS256 签发 | 家长登录 | ✅ 已就绪 |
|
||
| 2 | `POST /v1/iam/login` | 家长登录 | ✅ 已就绪 |
|
||
| 3 | `GET /v1/iam/children` | 获取绑定的学生列表 | ✅ 已就绪 |
|
||
| 4 | `GET /v1/iam/me` | 获取家长个人信息 | ✅ 已就绪 |
|
||
|
||
### 3.9 admin-portal(ai16 负责)— 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 服务已全量就绪,所有下游模块可开始真实联调。**
|