fix: 对齐 authz 认证链路
This commit is contained in:
+27
-24
@@ -22,9 +22,14 @@
|
||||
当前网关对以下路径做了“公共放行”:
|
||||
|
||||
- `/healthz`(直返 200,用于探针)
|
||||
- `POST /api/users/login`
|
||||
- `POST /api/users/register`
|
||||
- `POST /api/email/verification-code/send`(注册/登录前发送验证码)
|
||||
- `POST /api/v1/auth/login`
|
||||
- `POST /api/v1/auth/register`
|
||||
- `POST /api/v1/auth/forgot-password`
|
||||
- `POST /api/v1/auth/reset-password`
|
||||
- `POST /api/v1/auth/forgot-password/send`
|
||||
- `POST /api/v1/email/verification-code/send`
|
||||
|
||||
此外,当前配置还对一批只读接口做了 JWT 白名单豁免,例如 `GET /api/v1/games*`、`GET /api/v1/players*`、`GET /api/v1/services*`、`GET /api/v1/posts*`、`GET /api/v1/shops*` 以及部分 `GET /api/v1/users/*` 子路径。精确范围以 `deploy/k8s/envoy/envoy.yaml` 中的 `jwt_authn.rules` 为准。
|
||||
|
||||
实现方式:
|
||||
|
||||
@@ -60,27 +65,24 @@
|
||||
- Envoy 内置认证过滤器(如 `jwt_authn`、`ext_authz`)要求固定协议。
|
||||
- `ext_authz` 的 gRPC 需要实现 Envoy 标准服务 `envoy.service.auth.v3.Authorization`,不是业务自定义的 `pb.usercenter/ValidateToken`。
|
||||
|
||||
可行方案(推荐顺序):
|
||||
当前仓库已经采用 `authz-adapter` 方案:Envoy 先做 `jwt_authn`,再通过 `ext_authz` 调用 `authz-adapter`,由它内部调用 `user-rpc.ValidateToken` 做会话态二次校验。
|
||||
|
||||
1. **推荐**:新增一个 `authz-adapter` 服务,实现 Envoy `ext_authz` 协议,内部再调用 `user-rpc.ValidateToken`。
|
||||
2. 备选:提供一个内部 HTTP 鉴权端点(例如 user-api internal route),Envoy 通过 `ext_authz` HTTP 模式或 Lua `httpCall()` 调用。
|
||||
|
||||
如果要走方案 1(推荐),你需要补齐:
|
||||
当前链路包含:
|
||||
|
||||
- `authz-adapter` 服务(实现 Envoy `CheckRequest/CheckResponse`)
|
||||
- Envoy 新增 `ext_authz` filter 与对应 cluster
|
||||
- 鉴权透传头约定(至少 `x-auth-user-id`、`x-auth-is-admin`)
|
||||
- Envoy `ext_authz` filter 与 `authz_adapter_cluster`
|
||||
- `jwt_authn` 注入 `x-auth-user-id`、`x-auth-is-admin`
|
||||
- `authz-adapter` 透传 `x-auth-user-id`、`x-auth-role-type`
|
||||
- 失败码与错误体规范(401/403)
|
||||
- 性能与可用性策略(超时、失败回退、缓存)
|
||||
|
||||
### 4) 与你现有 `ValidateTokenLogic` 的一致性提醒
|
||||
|
||||
当前 `app/users/rpc/internal/logic/validateTokenLogic.go` 中:
|
||||
|
||||
- 代码使用 `jwt:%v` 格式拼接 `redisKey`
|
||||
- 但 `JwtManager.Valid()` 需要传入的是 **JWT token 字符串本身**
|
||||
- `JwtManager.Valid()` 负责验证 JWT 字符串本身
|
||||
- 当前逻辑还会校验 JWT payload 中的 `UserId` 与请求传入的 `userId` 一致,再查询数据库回填 `RoleType`
|
||||
|
||||
这意味着若后续接入 `ext_authz` 并调用该逻辑,建议先修正这段逻辑,避免认证结果偏差。
|
||||
这意味着当前 `ext_authz -> user-rpc.ValidateToken` 链已经具备 token 有效性和 userId 一致性校验。
|
||||
|
||||
---
|
||||
|
||||
@@ -100,12 +102,13 @@
|
||||
|
||||
## 前端接入示例(邮箱验证码)
|
||||
|
||||
以下示例基于你当前网关与服务配置:
|
||||
以下示例基于当前 K8s 网关配置:
|
||||
|
||||
- 登录:`POST /api/users/login`(公共放行)
|
||||
- 发送验证码:`POST /api/email/verification-code/send`(公共放行,无需登录)
|
||||
- CSRF 头:`XSRF-TOKEN`(请求头)
|
||||
- 登录:`POST /api/v1/auth/login`(公共放行)
|
||||
- 发送验证码:`POST /api/v1/email/verification-code/send`(公共放行,无需登录)
|
||||
- CSRF 头:`xsrf-token`(请求头)
|
||||
- CSRF Cookie:`__Host-XSRF-TOKEN`(可读)
|
||||
- CSRF Guard Cookie:`__Host-XSRF-GUARD`(`HttpOnly`)
|
||||
- JWT Cookie:`JToken`(`HttpOnly`,前端不可读,但会随请求自动携带)
|
||||
|
||||
> 注意:当前 Envoy 给 CSRF Cookie 设置了 `Secure` + `SameSite=Strict`。前端必须走 **HTTPS 且同站点** 才能稳定工作。
|
||||
@@ -113,7 +116,7 @@
|
||||
### 接入流程
|
||||
|
||||
1. 先发一个安全方法请求(GET),让 Envoy 下发 XSRF 双 Cookie。
|
||||
2. 注册场景可直接调用发送验证码接口,仅需携带 `XSRF-TOKEN`。
|
||||
2. 注册场景可直接调用发送验证码接口,仅需携带 `xsrf-token`。
|
||||
3. 登录场景可先调用登录接口拿 `JToken`,后续访问受保护接口时自动携带。
|
||||
|
||||
### 前端示例(TypeScript + fetch)
|
||||
@@ -136,12 +139,12 @@ async function primeXsrfCookies() {
|
||||
|
||||
async function login(username: string, password: string) {
|
||||
const xsrfToken = getCookie("__Host-XSRF-TOKEN");
|
||||
const res = await fetch(`${API_BASE}/api/users/login`, {
|
||||
const res = await fetch(`${API_BASE}/api/v1/auth/login`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"XSRF-TOKEN": xsrfToken,
|
||||
"xsrf-token": xsrfToken,
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
@@ -161,12 +164,12 @@ type SendCodeReq = {
|
||||
|
||||
async function sendVerificationCode(req: SendCodeReq) {
|
||||
const xsrfToken = getCookie("__Host-XSRF-TOKEN");
|
||||
const res = await fetch(`${API_BASE}/api/email/verification-code/send`, {
|
||||
const res = await fetch(`${API_BASE}/api/v1/email/verification-code/send`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"XSRF-TOKEN": xsrfToken,
|
||||
"xsrf-token": xsrfToken,
|
||||
},
|
||||
body: JSON.stringify(req),
|
||||
});
|
||||
@@ -235,7 +238,7 @@ kubectl get cm -n juwan envoy-config
|
||||
kubectl port-forward -n juwan svc/envoy-gateway 8080:80 &
|
||||
|
||||
# 测试
|
||||
curl http://localhost:8080/api/users/login
|
||||
curl http://localhost:8080/healthz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user