登录页去掉订阅口令:订阅接口认后台会话 + editor-api 反代

- Worker 侧 requireAuth 新增两条通道:① Authorization 管理员会话(CF 版后台
  登录后订阅模块免口令);② X-Editor-Token 共享令牌(服务端到服务端)。
  原 ?token=/Cookie 通道保留,RSS 阅读器与友圈页不受影响
- editor-api 新增订阅反代(/api/feeds|links|link-apply):国内机后台的
  订阅源/友链由本机带共享令牌去 CF 取,前端不再持有任何口令;GET 幂等重试
  抗跨境抖动
- 登录页只留账号+密码(CF 版与国内机版统一);国内机后台侧栏新增订阅中心
  入口;RSS_TOKEN / LS_RSS 前端残留全部清理
This commit is contained in:
zqlit committed 2026-10-04 23:57:02 +08:00
1 parent a11631faa6
commit 18a4882577
4 files changed
+114 -51

No files matched your search

+30 -2
View File
@@ -2,12 +2,14 @@
// 把原 EdgeOne 每个 api/*.js 里重复的 requireAuth / respond / corsOptions 收拢到一处
import type { Env } from '../../types';
import { getAdminUsers } from '../db';
import { userFromToken } from '../session';
export const CORS_HEADERS = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
} as const;
export function respond(data: unknown, status = 200): Response {
@@ -18,8 +20,34 @@ export function corsOptions(): Response {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
/** 校验站点口令:URL ?token= / Cookie site_token=。KV 无口令时放行(与原实现一致)。 */
/**
* 订阅模块的鉴权。三条通道,满足其一即可:
*
* ① 后台管理员会话(Authorization: Bearer …)
* —— 登录后台之后,订阅/友链这些模块不该再让人手填一遍口令。
* 后台里那个「订阅口令」输入框已经被这次改造干掉了。
*
* ② 服务端到服务端(X-Editor-Token == 环境里的共享令牌)
* —— 国内机后台(writeapi.usj.cc)的订阅请求由本机 editor-api 反代过来,
* 它带着自己的共享令牌。这样国内机不必再存第三份口令。
*
* ③ 站点口令(URL ?token= 或 Cookie site_token=)
* —— 原有通道,留给 RSS 阅读器、友圈页这类外部调用方,行为不变。
*/
export async function requireAuth(request: Request, env: Env): Promise<boolean> {
const bearer = request.headers.get('Authorization');
if (bearer) {
const user = await userFromToken(env, bearer);
if (user) {
if (user.is_admin) return true;
const admins = await getAdminUsers(env);
if (admins.some((a) => a.email && a.email.toLowerCase() === user.email.toLowerCase())) return true;
}
}
const shared = request.headers.get('X-Editor-Token') || '';
if (shared && env.EDITOR_TOKEN && shared === env.EDITOR_TOKEN) return true;
const url = new URL(request.url);
const cookie = request.headers.get('Cookie') || '';
const cookieMatch = cookie.match(/site_token=([^;]+)/);