Files
Edu/services/iam/README.md
SpecialX a35e759d64 feat(iam): 完整实现 iam 身份认证与权限服务
包含 jwt/jwks/audit/grpc、rbac、cache、redis/kafka 配置等完整实现
2026-07-10 19:09:39 +08:00

136 lines
6.9 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 Service
身份与访问管理服务Identity and Access Management
> 版本v0.2.0(对齐 coord-final-decisions I1-I8 + president §2.15/§2.16/§3.2/§5.5
> 详细设计见 [02-architecture-design.md](./docs/02-architecture-design.md)
## 职责
- 用户注册 / 登录 / 刷新令牌 / 登出
- JWT RS256 签发access 15min + refresh 7dayjti 黑名单)
- 角色Role与权限Permission管理三层角色模型system/organization/temporary
- DataScope 6 级数据范围self/subject/class/grade/school/all
- 视口Viewport配置查询
- 学生-家长关系管理(`GetChildrenByParent`
- 审计日志(`iam_user_audit_log` + `AuditCreated` 事件)
- JWKS 公钥暴露(供 api-gateway 验签)
- 双入口REST `/v1/iam/*` + gRPC 50052package `next_edu_cloud.iam.v1`12 RPC
## 技术栈
- NestJS 10 + TypeScriptESMNodeNext
- Drizzle ORM + MySQL10 张表)
- bcrypt 密码哈希cost ≥ 12
- jsonwebtoken RS256本地文件密钥
- ioredis权限缓存 TTL 5min + token jti 黑名单)
- kafkajs + shared-ts OutboxModule事务性事件发布
- @nestjs/microservices + @grpc/grpc-jsgRPC server
- pino 日志 / prom-client 指标 / OpenTelemetry 链路
## 端口
| 服务 | 端口 | 备注 |
| -------- | ----- | ------------------------ |
| iam HTTP | 3002 | REST 入口(`PORT` |
| iam gRPC | 50052 | gRPC 入口(`GRPC_PORT` |
## 环境变量
| 变量 | 说明 | 默认值 |
| ----------------------------- | ------------------------------ | ---------------- |
| `PORT` | HTTP 端口 | `3002` |
| `GRPC_PORT` | gRPC 端口 | `50052` |
| `DATABASE_URL` | MySQL 连接串 | — |
| `REDIS_URL` | Redis 连接串 | — |
| `IAM_PRIVATE_KEY_PATH` | RS256 私钥文件路径 | — |
| `IAM_PUBLIC_KEY_PATH` | RS256 公钥文件路径 | — |
| `JWT_ISSUER` | JWT 签发者 | `next-edu-cloud` |
| `JWT_AUDIENCE` | JWT 受众 | `next-edu-cloud` |
| `JWT_KEY_ID` | 密钥 IDkid用于 JWKS 轮换) | `iam-rs256-v1` |
| `ACCESS_TOKEN_TTL` | access_token TTL | `15m` |
| `REFRESH_TOKEN_TTL_DAYS` | refresh_token TTL | `7` |
| `KAFKA_BROKERS` | Kafka broker 列表(逗号分隔) | — |
| `KAFKA_CLIENT_ID` | Kafka client ID | `iam-service` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTel OTLP 端点(可选) | — |
| `LOG_LEVEL` | 日志级别 | `info` |
| `NODE_ENV` | 环境标识 | `development` |
## REST API
| Method | Path | 权限 | 说明 |
| ------ | ------------------------------- | ----------------- | ---------------------------------- |
| POST | `/v1/iam/register` | 公开 | 注册 |
| POST | `/v1/iam/login` | 公开 | 登录 |
| POST | `/v1/iam/refresh` | 公开 | 刷新令牌(轮换 + 旧 jti 加黑名单) |
| POST | `/v1/iam/logout` | `IAM_USER_READ` | 登出 |
| GET | `/v1/iam/me` | `IAM_USER_READ` | 当前用户信息 |
| GET | `/v1/iam/viewports` | `IAM_USER_READ` | 当前用户视口 |
| GET | `/v1/iam/permissions/effective` | `IAM_USER_READ` | 当前用户有效权限 |
| GET | `/v1/iam/children` | `IAM_USER_READ` | 家长的孩子列表 |
| GET | `/v1/iam/roles` | `IAM_ROLE_MANAGE` | 角色列表 |
| GET | `/v1/iam/permissions` | `IAM_ROLE_MANAGE` | 权限点列表 |
| GET | `/v1/iam/audit` | `IAM_AUDIT_READ` | 审计日志 |
| GET | `/v1/iam/.well-known/jwks.json` | 公开 | RS256 公钥 JWK Set |
## gRPC API
12 RPCproto 定义见 `packages/shared-proto/proto/iam.proto`package `next_edu_cloud.iam.v1`
`Register` / `Login` / `RefreshToken` / `Logout` / `GetUserInfo` / `BatchGetUsers` / `GetEffectivePermissions` / `GetEffectiveAccess` / `GetEffectiveDataScope` / `GetViewports` / `GetPublicKey` / `GetChildrenByParent`
## 健康检查
| 端点 | 用途 | 鉴权 |
| -------------- | ------------------------------------------------------------------------- | ---- |
| `GET /healthz` | 存活探针liveness仅返回进程状态 | 无 |
| `GET /readyz` | 就绪探针readiness检查 DB/Redis/Kafka/JWKS/gRPC 5 依赖,失败返回 503 | 无 |
## 数据表10 张)
| 表名 | 用途 |
| ----------------------- | --------------------------- |
| `iam_users` | 用户主表 |
| `iam_roles` | 角色表role_type + level |
| `iam_user_roles` | 用户-角色绑定 |
| `iam_permissions` | 权限点表 |
| `iam_role_permissions` | 角色-权限映射 |
| `iam_refresh_tokens` | refresh token含 jti |
| `iam_role_viewports` | 角色-视口配置(含 level |
| `iam_student_guardians` | 学生-家长关系 |
| `iam_user_audit_log` | 审计日志 |
| `iam_password_history` | 密码重用限制 |
DDL + 种子数据见 `scripts/iam-init.sql`
## Kafka 事件
| Topic | 事件 |
| ----------------------- | -------------- |
| `edu.iam.user.events` | `UserCreated` |
| `edu.iam.role.events` | `RoleChanged` |
| `edu.iam.audit.created` | `AuditCreated` |
通过 shared-ts `OutboxModule` 事务性发布at-least-once + idempotent producer
## 开发
```bash
# 安装依赖
pnpm install
# 初始化数据库(需先启动 MySQL + Redis + Kafka
mysql -u root -p < scripts/iam-init.sql
# 生成 RS256 密钥对
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
# 启动开发服务
pnpm --filter @edu/iam-service dev
# 质量校验
pnpm --filter @edu/iam-service lint
pnpm --filter @edu/iam-service typecheck
```