# 国内与海外 JWT/JWKS 冻结契约 ## 双轨边界 ### 国内现有链路 - 登录、刷新、退出和代登录接口保持原契约,不修改 `TokenResponse`。 - 签名算法保持 `HS256`,继续使用 `JWT_SECRET`。 - Access Token 默认有效期保持 24 分钟,Refresh Token 默认有效期保持 7 天。 - 业务服务继续使用国内 HMAC 验签与 Redis 会话校验,账号停用、退出和 Token 版本失效规则不变。 - 国内 Token 保持现有 snake_case 声明,不增加海外 `aud`,也不要求配置 RSA/JWK。 ### 海外尾程链路 - 海外能力默认关闭:`OVERSEAS_JWT_ENABLED=false`。 - 已通过国内 HS256 与 Redis 校验的登录用户调用 `POST /api/auth/overseas/token`,兑换独立的海外短时 Token。 - 海外 Token 使用 `RS256`,默认有效期 15 分钟,不签发 Refresh Token。 - 尾程必须配置 `baiyue.security.jwt-mode=jwks` 和 `baiyue.security.session-mode=claims`,只做 JWKS 验签和本地安全投影校验,不创建或访问国内 Redis 会话校验器。 - 海外功能未启用时,兑换接口返回“海外认证未启用”;JWKS Controller、海外签发服务和 `overseasJwtEncoder` 均不创建,Auth 仍可正常启动并签发国内 HS256 Token。 ## 海外签发契约 - `issuer`:`auth-service` - `audience`:`lastleg-api` - 算法白名单:仅 `RS256` - Access Token 默认有效期:15 分钟 - 兑换接口:`POST /api/auth/overseas/token` - JWKS 路径:`/api/auth/.well-known/jwks.json` - Auth 直连地址:`http://{auth-host}:9100/api/auth/.well-known/jwks.json` - JWKS HTTP 缓存:5 分钟,响应 `Cache-Control: public, max-age=300` 海外 Token 的 JSON 声明名称和类型固定如下: | 声明 | JSON 类型 | 说明 | |---|---|---| | `sub` | string | 用户 ID 的字符串形式 | | `jti` | string | Token 唯一标识 | | `iat` | number | 签发时间 | | `exp` | number | 过期时间 | | `aud` | string array | 固定包含 `lastleg-api` | | `userId` | number | 认证用户 ID | | `tenantId` | number | 当前客户 ID;平台账号为平台作用域值 | | `appCode` | string | `PLATFORM` 或 `MERCHANT` | | `roles` | string array | 当前角色编码快照 | | `authorities` | string array | 当前权限编码快照 | | `permissionVersion` | number | IAM 单调权限版本 | 海外 Token 从 V1 起只使用上述 camelCase 自定义声明,不读取国内 snake_case 声明。 ## 海外配置 ```yaml baiyue: security: overseas-jwt: enabled: ${OVERSEAS_JWT_ENABLED:false} issuer: ${OVERSEAS_JWT_ISSUER:auth-service} audience: ${OVERSEAS_JWT_AUDIENCE:lastleg-api} rsa-jwk-set: ${OVERSEAS_JWT_RSA_JWK_SET:} current-kid: ${OVERSEAS_JWT_CURRENT_KID:} access-token-ttl: ${OVERSEAS_ACCESS_TOKEN_TTL:15m} ``` 只有显式启用海外能力时才校验 `OVERSEAS_JWT_RSA_JWK_SET` 和 `OVERSEAS_JWT_CURRENT_KID`。启用后配置不合法必须启动失败,避免错误密钥签发。 ## 密钥轮换 - JWK Set 只允许 RSA 密钥。 - `OVERSEAS_JWT_CURRENT_KID` 必须指向唯一的当前签名私钥,JWT Header 写入该 `kid`。 - 非当前密钥只能保留公钥;JWKS 只发布公钥,不得输出私钥参数。 - 轮换时同时发布当前公钥和上一公钥,上一公钥至少保留 20 分钟,即 15 分钟最大 Token 生命周期加 5 分钟 JWKS 缓存。 - 重叠期结束后移除上一公钥,禁止复用历史 `kid`。 ## IAM 安全事件 安全事件的 `eventType`、版本、状态枚举和 payload 以 `iam/SECURITY-EVENT-AUDIT.md` 为唯一契约。尾程维护用户状态、客户状态和权限版本的本地投影,请求期间不反向同步访问国内 IAM。