perf(struct): ddd

This commit is contained in:
2026-02-03 17:31:08 +08:00
parent 202b5eaad5
commit 4a071bd7c8
64 changed files with 1214 additions and 1189 deletions

View File

@@ -7,11 +7,12 @@
- 登录页:`{IAM_FRONT_BASE_URL}/login?clientId={clientId}&tenantId={tenantId}&callback={encodeURIComponent(redirectUri)}`
- 授权码codeJWTHS256有效期 5 分钟Redis 单次使用
- 换取 token业务服务端携带 `clientSecret` 调用
- `POST {IAM_SERVICE_BASE_URL}/iam/api/v1/auth/code2token`
- `POST {IAM_SERVICE_BASE_URL}/api/v1/auth/code2token`(外部第三方:必须携带 tenant_id 并校验 clientId/clientSecret
- `POST {IAM_SERVICE_BASE_URL}/api/v1/internal/auth/code2token`(内部服务:需 `X-Internal-Token` 预共享密钥,不强制 tenant_id
- 签发授权码:由 IAM 服务端完成(校验 redirectUri 是否在该 clientId 的 allowlist 中)
- `POST {IAM_SERVICE_BASE_URL}/iam/api/v1/auth/login-code`
- token 刷新:`POST {IAM_SERVICE_BASE_URL}/iam/api/v1/auth/refresh`
- 退出:`POST {IAM_SERVICE_BASE_URL}/iam/api/v1/auth/logout`
- `POST {IAM_SERVICE_BASE_URL}/api/v1/auth/login-code`
- token 刷新:`POST {IAM_SERVICE_BASE_URL}/api/v1/auth/refresh`
- 退出:`POST {IAM_SERVICE_BASE_URL}/api/v1/auth/logout`
## 2. 业务 Next.js前端接入中间件跳转登录
@@ -20,45 +21,46 @@
在业务项目根目录创建 `/src/middleware.ts`
```ts
import { NextRequest, NextResponse } from "next/server"
import { NextRequest, NextResponse } from "next/server";
function isExpired(jwt: string): boolean {
const parts = jwt.split(".")
if (parts.length < 2) return true
const normalized = parts[1].replace(/-/g, "+").replace(/_/g, "/")
const padLen = (4 - (normalized.length % 4)) % 4
const json = atob(normalized + "=".repeat(padLen))
const payload = JSON.parse(json) as { exp?: number }
if (!payload.exp) return true
return Math.floor(Date.now() / 1000) >= payload.exp
const parts = jwt.split(".");
if (parts.length < 2) return true;
const normalized = parts[1].replace(/-/g, "+").replace(/_/g, "/");
const padLen = (4 - (normalized.length % 4)) % 4;
const json = atob(normalized + "=".repeat(padLen));
const payload = JSON.parse(json) as { exp?: number };
if (!payload.exp) return true;
return Math.floor(Date.now() / 1000) >= payload.exp;
}
export function middleware(req: NextRequest) {
const tenantId = req.headers.get("x-tenant-id") ?? ""
const accessToken = req.cookies.get("accessToken")?.value ?? ""
const tenantId = req.headers.get("x-tenant-id") ?? "";
const accessToken = req.cookies.get("accessToken")?.value ?? "";
if (!accessToken || isExpired(accessToken)) {
const currentUrl = req.nextUrl.clone()
const currentUrl = req.nextUrl.clone();
const callback = `${process.env.CMS_SERVICE_BASE_URL}/auth/callback?next=${encodeURIComponent(
currentUrl.toString(),
)}`
)}`;
const loginUrl = `${process.env.IAM_FRONT_BASE_URL}/login?clientId=${encodeURIComponent(
process.env.CMS_CLIENT_ID ?? "",
)}&tenantId=${encodeURIComponent(
tenantId,
)}&callback=${encodeURIComponent(callback)}`
return NextResponse.redirect(loginUrl, 302)
)}&callback=${encodeURIComponent(callback)}`;
return NextResponse.redirect(loginUrl, 302);
}
return NextResponse.next()
return NextResponse.next();
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico|api/public).*)"],
}
};
```
说明:
- 示例使用 cookie `accessToken`;你也可以改为本地存储或自定义 header。
- 校验是否过期仅做 payload 解析(不验签);服务端真正鉴权仍应使用 `auth-kit` + RS256 验签。
@@ -89,7 +91,7 @@ async fn sso_callback(Query(q): Query<CallbackQuery>) -> Redirect {
let http = reqwest::Client::new();
let resp = http
.post(format!("{}/iam/api/v1/auth/code2token", iam_base.trim_end_matches('/')))
.post(format!("{}/api/v1/auth/code2token", iam_base.trim_end_matches('/')))
.json(&serde_json::json!({
"code": q.code,
"clientId": client_id,
@@ -131,15 +133,16 @@ pub fn router() -> Router {
### 3.2 后端鉴权与自动刷新
推荐:
- 业务后端对受保护接口强制 `Authorization: Bearer <access_token>`(来自 cookie 或前端 header
- 过期时由业务后端调用 `POST /iam/api/v1/auth/refresh`,轮换 refresh token并回写 cookie。
- 过期时由业务后端调用 `POST /api/v1/auth/refresh`,轮换 refresh token并回写 cookie。
## 4. clientId / clientSecret 管理
由平台管理员通过 IAM 平台接口创建与轮换(仅示例,实际需要具备平台权限码 `iam:client:*`
```bash
curl -X POST "$IAM_SERVICE_BASE_URL/iam/api/v1/platform/clients" \
curl -X POST "$IAM_SERVICE_BASE_URL/api/v1/platform/clients" \
-H "Authorization: Bearer $PLATFORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "clientId": "cms", "name": "CMS", "redirectUris": ["https://cms-api.example.com/auth/callback"] }'
@@ -148,14 +151,14 @@ curl -X POST "$IAM_SERVICE_BASE_URL/iam/api/v1/platform/clients" \
轮换:
```bash
curl -X POST "$IAM_SERVICE_BASE_URL/iam/api/v1/platform/clients/cms/rotate-secret" \
curl -X POST "$IAM_SERVICE_BASE_URL/api/v1/platform/clients/cms/rotate-secret" \
-H "Authorization: Bearer $PLATFORM_TOKEN"
```
更新允许回调地址redirectUris
```bash
curl -X PUT "$IAM_SERVICE_BASE_URL/iam/api/v1/platform/clients/cms/redirect-uris" \
curl -X PUT "$IAM_SERVICE_BASE_URL/api/v1/platform/clients/cms/redirect-uris" \
-H "Authorization: Bearer $PLATFORM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "redirectUris": ["https://cms-api.example.com/auth/callback"] }'