136 lines
6.9 KiB
Markdown
136 lines
6.9 KiB
Markdown
# 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 7day,jti 黑名单)
|
||
- 角色(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 50052(package `next_edu_cloud.iam.v1`,12 RPC)
|
||
|
||
## 技术栈
|
||
|
||
- NestJS 10 + TypeScript(ESM,NodeNext)
|
||
- Drizzle ORM + MySQL(10 张表)
|
||
- bcrypt 密码哈希(cost ≥ 12)
|
||
- jsonwebtoken RS256(本地文件密钥)
|
||
- ioredis(权限缓存 TTL 5min + token jti 黑名单)
|
||
- kafkajs + shared-ts OutboxModule(事务性事件发布)
|
||
- @nestjs/microservices + @grpc/grpc-js(gRPC 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` | 密钥 ID(kid,用于 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 RPC,proto 定义见 `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
|
||
```
|