From e7db6762fd50f49d63d141a03c4b4dbc632f6c22 Mon Sep 17 00:00:00 2001 From: bigcode Date: Wed, 30 Sep 2026 17:26:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(email):=20=E5=BC=80=E5=90=AF=20Email=20Rout?= =?UTF-8?q?ing=20=E6=94=B9=E7=94=A8=20PUT,=E5=B9=B6=E8=A1=A5=E4=B8=8A=20zo?= =?UTF-8?q?ne-settings.write=20=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POST /zones/{id}/email/routing 不是有效路由,Cloudflare 返回 10405 Method not allowed for this authentication scheme。正确接口是 PUT /zones/{id}/email/routing(Apply Email Routing settings); POST .../email/routing/enable 能用但官方已标 Deprecated。 该接口的 Accepted Permission 是 Zone Settings Write,而不是 Email Routing 权限族 —— 权限名和接口所属资源组对不上,Email Routing 四个权限全勾也不够。 - CF_OAUTH_SCOPES_DEFAULT / 探测候选集加 zone-settings.write;设置页文案同步 - cfapi 的 API 错误带上 Cloudflare 错误码(如 10405),便于区分路径错与权限错 - cf-mock 对非 PUT 的 /email/routing 返回 10405,旧写法会被打回 - 88/88 测试 --- README.md | 2 +- console/frontend/src/api.ts | 3 +- .../frontend/src/components/SettingsModal.tsx | 6 ++-- console/src/services/cfapi.ts | 36 +++++++++++++++---- docs/02_CLOUDFLARE_OAUTH.md | 15 +++++++- package.json | 2 +- tests/cf-mock.ts | 11 ++++++ tests/oauth.test.ts | 27 ++++++++++---- 8 files changed, 83 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e1a0565..832c0ff 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ WmailHub/ - **Redirect URL**:`https://wmailhub.adx9.com/api/oauth/cloudflare/callback` - **Client URI**:`https://wmailhub.adx9.com`(必须是 Console 站点域名),并按提示加 TXT 记录完成域名校验 - **Promote to public**:私有 App 无法被授权 - - **Scopes**(`zone.read` / `workers-scripts.write` / `email-routing-rule.write`):**点号分隔**,冒号写法(`account:read`)是 wrangler 的第一方简写,第三方 client 会被拒;这三项就够,账号 id 与账号名随 `GET /zones` 的每个 zone 一起返回,不需要账号级权限 + - **Scopes**(`zone.read` / `workers-scripts.write` / `email-routing-rule.write` / `zone-settings.write`):**点号分隔**,冒号写法(`account:read`)是 wrangler 的第一方简写,第三方 client 会被拒;账号 id 与账号名随 `GET /zones` 的每个 zone 一起返回,不需要账号级权限;注意最后一项 Zone Settings Write 是**开启 Email Routing** 用的,不勾会在「设置 Email Workers」时报 `10405` 配好后到设置页点「检测授权配置」确认,再点账号页「添加账号」。Client ID / Secret 有两个配置位置,任一即可: - **推荐**:部署后登录 Console → 设置 →「Cloudflare 接入」填写,Secret 加密入库,改完立即生效,以后换 client 也不用重新部署; diff --git a/console/frontend/src/api.ts b/console/frontend/src/api.ts index f845357..0b34534 100644 --- a/console/frontend/src/api.ts +++ b/console/frontend/src/api.ts @@ -335,7 +335,8 @@ export interface OAuthPreflightResult { } /** 本应用默认需要的 scope(点号分隔)——与后端 CF_OAUTH_SCOPES_DEFAULT 保持一致 */ -export const CF_OAUTH_SCOPES_DEFAULT = "zone.read workers-scripts.write email-routing-rule.write"; +export const CF_OAUTH_SCOPES_DEFAULT = + "zone.read workers-scripts.write email-routing-rule.write zone-settings.write"; /** 授权配置自检:探测 Cloudflare 授权端点是否接受当前配置(不产生授权) */ export const oauthPreflight = () => api("/api/oauth/cloudflare/preflight"); diff --git a/console/frontend/src/components/SettingsModal.tsx b/console/frontend/src/components/SettingsModal.tsx index 216a703..dec230c 100644 --- a/console/frontend/src/components/SettingsModal.tsx +++ b/console/frontend/src/components/SettingsModal.tsx @@ -390,11 +390,13 @@ function CloudflareTab({ info, onSaved }: { info: SettingsInfo; onSaved: () => v <> Cloudflare 的 OAuth scope 是点号分隔(zone.read),冒号写法(zone:read)是 wrangler 的 第一方简写,第三方客户端会被判 invalid_scope。必须与 OAuth App 里勾选的权限一致;检测按钮会 - 直接告诉你哪些已授权、哪些还要补勾。三项就够:账号名随 zone 一起返回,不需要账号级权限。 + 直接告诉你哪些已授权、哪些还要补勾。四项分别对应:发现域名、上传 Email Worker、改 catch-all + 规则、开启 Email Routing(最后这项在选择器里叫 Zone Settings Write,不归 Email + Routing 管,漏了会在「设置 Email Workers」时才报错)。 } > - +