# 本地端到端联调(iam-service + cms-service) 目标: - 生成临时 RSA 公私钥供 iam-service 使用(RS256) - 启动 iam-service(签发 token、发布 JWKS、提供权限裁决 `/authorize/check`) - 启动 cms-service(本地验签 + 调用 IAM 做权限裁决) - 在两个服务的 Scalar 页面完成:创建租户 → 注册用户 → 登录 → 调用 CMS 资源接口,验证“认证/权限由 IAM 控制” > 本文不要求修改任何业务代码;只需要本地导出环境变量或创建 `.env` 文件。 ## 0. 前置条件 - Rust(支持 edition 2024)与 Cargo - PostgreSQL(本机或 Docker),并可使用 `psql` - `openssl` 端口默认: - iam-service:3000 - cms-service:3100 ## 1. 准备数据库(推荐:Docker 一键起 PostgreSQL) 启动 PostgreSQL: ```bash docker run --rm -d --name local-pg \ -e POSTGRES_PASSWORD=postgres \ -p 5432:5432 \ postgres:16 ``` 创建 iam/cms 两个数据库与用户(示例账号,可按需调整): ```bash docker exec -i local-pg psql -U postgres <<'SQL' CREATE USER iam_service_user WITH PASSWORD 'iam_service_password'; CREATE DATABASE iam_service_db OWNER iam_service_user; GRANT ALL PRIVILEGES ON DATABASE iam_service_db TO iam_service_user; CREATE USER cms_service_user WITH PASSWORD 'cms_service_password'; CREATE DATABASE cms_service_db OWNER cms_service_user; GRANT ALL PRIVILEGES ON DATABASE cms_service_db TO cms_service_user; SQL ``` 准备连接串(后续会分别用于两服务): - IAM:`postgres://iam_service_user:iam_service_password@127.0.0.1:5432/iam_service_db` - CMS:`postgres://cms_service_user:cms_service_password@127.0.0.1:5432/cms_service_db` ## 2. 生成临时 RSA 公私钥(RS256) ```bash KEY_DIR="$(mktemp -d)" openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out "$KEY_DIR/jwt_private_key.pem" openssl pkey -in "$KEY_DIR/jwt_private_key.pem" -pubout -out "$KEY_DIR/jwt_public_key.pem" chmod 600 "$KEY_DIR/jwt_private_key.pem" chmod 644 "$KEY_DIR/jwt_public_key.pem" echo "KEY_DIR=$KEY_DIR" ``` 说明: - 私钥:PKCS#8 PEM(`BEGIN PRIVATE KEY`) - 公钥:PKCS#8 公钥 PEM(`BEGIN PUBLIC KEY`) - 该目录是临时目录,重启/清理后会消失;适合本地联调 ## 3. 启动 iam-service(签发 token + JWKS + 权限裁决) 在一个终端中执行(建议在 `iam-service` 目录下): ```bash cd /home/shay/project/backend/iam-service export PORT=3000 export DATABASE_URL='postgres://iam_service_user:iam_service_password@127.0.0.1:5432/iam_service_db' # 用于 refresh token 指纹(不是 JWT 签名密钥),本地随便填一个即可 export JWT_SECRET='local-dev-refresh-token-pepper' export JWT_KEY_ID='local-dev' export JWT_PRIVATE_KEY_PEM="$(cat "$KEY_DIR/jwt_private_key.pem")" export JWT_PUBLIC_KEY_PEM="$(cat "$KEY_DIR/jwt_public_key.pem")" # 初始化/重建 DB(会清库重建,适合开发环境) BACKUP=0 ./scripts/db/rebuild_iam_db.sh cargo run ``` 启动后: - IAM Scalar:`http://127.0.0.1:3000/scalar` - JWKS:`http://127.0.0.1:3000/.well-known/jwks.json` ## 4. 启动 cms-service(本地验签 + 调 IAM 裁权) 在另一个终端中执行(建议在 `cms-service` 目录下): ```bash cd /home/shay/project/backend/cms-service export PORT=3100 export DATABASE_URL='postgres://cms_service_user:cms_service_password@127.0.0.1:5432/cms_service_db' export IAM_BASE_URL='http://127.0.0.1:3000' # CMS 默认会走 IAM_BASE_URL + /.well-known/jwks.json 拉取公钥 # 如需显式指定: # export IAM_JWKS_URL='http://127.0.0.1:3000/.well-known/jwks.json' # 初始化/重建 DB(会回滚并重建 cms schema;适合开发环境) ./scripts/db/rebuild_cms_db.sh cargo run ``` 启动后: - CMS Scalar:`http://127.0.0.1:3100/scalar` ## 5. 在 Scalar 中跑通“租户 → 注册 → 登录 → 调用 CMS 接口” ### 5.1 在 IAM Scalar 创建租户 打开 `http://127.0.0.1:3000/scalar`: 1) 调用 `POST /tenants/register` 示例 body: ```json { "name": "Tenant A" } ``` 从响应中拿到 `tenant_id`(UUID)。 ### 5.2 在 IAM Scalar 注册首个用户(自动 Admin + CMS 权限) 调用 `POST /auth/register`: - Header:`X-Tenant-ID: ` - Body: ```json { "email": "admin@example.com", "password": "Passw0rd!" } ``` 重要说明: - 该租户的**首个用户**会自动触发 bootstrap:创建/获取 `Admin` 角色,并授予该租户下的全量非 `iam:*` 权限(包含 `cms:*` 权限),再绑定给该用户。 ### 5.3 在 IAM Scalar 登录拿 token 调用 `POST /auth/login`: - Header:`X-Tenant-ID: ` - Body: ```json { "email": "admin@example.com", "password": "Passw0rd!" } ``` 保存响应中的: - `access_token` - `refresh_token`(可选,用于测试刷新) ### 5.4 在 CMS Scalar 调用资源接口(验证由 IAM 裁权) 打开 `http://127.0.0.1:3100/scalar`,选择任意需要权限的接口,例如: - `POST /v1/columns`(需要 `cms:column:write`) 在请求中设置: - `Authorization: Bearer ` - `X-Tenant-ID: ` 若一切正常: - CMS 会先本地验签 token(auth-kit) - 然后调用 IAM 的 `POST /authorize/check` 判断权限 - IAM 返回 allowed 后,CMS 才会执行业务写入 验证建议: - 观察 iam-service 控制台日志:应能看到 `/authorize/check` 的请求 - 如将 `access_token` 改成无效字符串,CMS 会直接返回 401(本地验签失败,不会去请求 IAM) ## 6. 常见问题(本地联调) ### 6.1 CMS 返回 401 MissingAuthHeader - 检查是否在 CMS 请求里设置了 `Authorization: Bearer ` - 检查 token 是否复制完整(不要带引号/空格) ### 6.2 CMS 返回 400 Missing X-Tenant-ID header - CMS 需要 `X-Tenant-ID` - 若同时提供 token + header,但 tenant_id 不一致会返回 403(tenant:mismatch) ### 6.3 CMS 返回 403 PermissionDenied - 表示 IAM 裁权拒绝(例如用户没有 `cms:*` 权限) - 你可以在 IAM 中调用 `GET /me/permissions` 查看当前用户权限