Skip to content

修复:鉴权、加密与登录流程的多项安全与体验问题 - #109

Closed
BAJJDY wants to merge 5 commits into
OpenListTeam:mainfrom
BAJJDY:main
Closed

BAJJDY wants to merge 5 commits into
OpenListTeam:mainfrom
BAJJDY:main

Conversation

@BAJJDY

@BAJJDY BAJJDY commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

问题

  1. 禁用用户的已签发 JWT 仍然有效
    authUserFromReq() 只校验用户是否存在,未检查 disabled 字段,与
    middlewares.ts 的 getUserFromContext() 行为不一致。管理员禁用某个账号
    (例如游客用户)后,该账号此前已签发的 JWT 仍然可用,最长持续到其
    exp(默认 7 天)。

  2. /me 对禁用账号返回笼统的 Unauthorized
    前端拿到 401 Unauthorized 无法区分「未登录」与「账号被禁用」,只能统一
    弹一个 Unauthorized 提示。

修复

  • authUserFromReq() 增加 disabled 判断,与 middlewares.ts 对齐:
  -  if (!user) return null
  +  if (!user || user.disabled) return null

• meHandler() 在账号被禁用时返回可区分的消息(未登录仍为 Unauthorized):

----diff-----
  -  message: "Unauthorized",
  +  message: !user ? "Unauthorized" : "Account is disabled",

影响面

• 禁用账号的 token 立即失效,不再有最长 7 天的宽限期;
• 未登录 / 正常登录路径行为不变;
• 前端可据 Account is disabled 做差异化提示(前端改动另行 PR)。

验证

•  创建游客用户并签发 token → 管理员禁用该用户 → 用旧 token 请求受保护接口 → 返回 401;
•  未登录请求 /me → 仍返回 Unauthorized;
•  正常用户请求 /me → 行为不变。

---
### 标题

fix(login): respect allow_guest, make settings reactive, and resume session

### 描述内容

```markdown
## 问题与修复(共 3 项,均在登录页)

### 1. 游客登录按钮在 `allow_guest=false` 时仍无条件渲染

登录页的「以游客身份浏览」按钮**无条件渲染**,后台关闭游客后依然显示。
现用 `<Show when={getSettingBool("allow_guest")}>` 包裹;同时把游客登录后的
跳转从 `searchParams.redirect || base_path` 收敛为 `base_path || "/"`,避免
游客被带到未授权页面。

```diff
-  <Button w="$full" colorScheme="accent" onClick={...}>
-    {t("login.use_guest")}
-  </Button>
+  <Show when={getSettingBool("allow_guest")}>
+    <Button w="$full" colorScheme="accent" onClick={...}>
+      {t("login.use_guest")}
+    </Button>
+  </Show>

2. 游客开关变更后登录页不生效(settings 非响应式)

store/settings.ts 用普通模块级对象存设置,getSetting() 不建立响应式依赖;
且退出登录是纯 SPA 跳转(Header.tsx 的 to("/@login?...")),登录页只
拿到 App 启动时的快照。因此管理员禁用游客后,登录页仍显示游客入口,直到整页
刷新才更新。

修复:

• settings 改用 createSignal,setSettings 改为合并更新,使每次

getSetting() 读取都建立响应式依赖;

• 新增 refreshSettings() 重拉 /public/settings;
• 登录页挂载时调用 refreshSettings(),拉取失败时静默保留旧值、不阻塞登录。

3. 已登录用户误入登录页时需重新输入账号密码

已登录(本地有有效 token)的用户若进入登录页并点击「登录」,会再次要求输入
账号密码。新增 TryResumeSession():先探测本地 token 是否有效
(GET /me)——

• 有效 → 直接按 redirect / base_path / "/" 跳回主页面(等价于刷新后的正常

登录态);

• 无效 → 清除过期 token,继续走原有账号密码 / WebAuthn 流程。

验证

•  后台关闭 allow_guest → 登录页不再显示游客入口(无需整页刷新);
•  后台开启 allow_guest → 游客入口恢复显示;
•  已登录状态访问 @login 并点击登录 → 直接跳回主页面,不再要求密码;
•  token 失效后进入登录页点击登录 → 正常走账号密码流程。

BAJJDY added 5 commits October 5, 2026 07:42
Also align wrangler.jsonc with the live Worker so CF Builds deploys to the existing service:
  - name: openlist-tsworkers -> openlist-worker
  - DB_DRIVER: auto -> kv (live binding is KV)
  - kv_namespaces: fill in the real namespace id

Verified locally:
  - tsc: 0 errors in changed files (pre-existing duplicate-identifier errors in db_cipher.test.ts are unrelated and untouched)
  - edge build: dist-server/api/[...route].js compiled authUserFromReq with the new (user || user.disabled) -> null short-circuit; isTokenRevoked(jti) check intact
  - frontend dist rebuilt from frontend repo main: style-Xdg_lEeV.css now ships 72 .solid-contextmenu style blocks (the online deploy was missing this file, breaking the right-click menu), and /@init + /public/init_status are present (Worker init protocol healthy)
…count 401

- fetch-frontend.mjs default FRONTEND_GIT_URL now points at
  BAJJDY/OpenList-Frontend (fork) so CF Builds compiles the fixed
  guest login UI. FRONTEND_GIT_URL still overrides it.
- meHandler returns "Account is disabled" instead of "Unauthorized"
  when the account exists but is disabled, so the frontend can tell
  apart “guest not enabled” from “invalid credentials”.
Sensitive fields (drive credentials, 2FA secrets, password hashes) were
written to KV in plaintext. Enable aes-256-gcm (enc:v2: envelope) so new
writes are sealed with the JWT_SECRET-derived key.

Reads are prefix-based, so existing plaintext entries keep working and
migrate to ciphertext on the next save. Syncs the repo with the Worker
binding so wrangler deploy no longer resets it to none.
Frontend fix lives in BAJJDY/OpenList-Frontend@fa96247:
- src/store/settings.ts: settings becomes a reactive signal + add refreshSettings()
- src/pages/login/index.tsx: call refreshSettings() on mount so the guest
  login button reflects the current allow_guest setting after SPA logout
The CF build runs scripts/fetch-frontend.mjs which clones this fork and
builds the frontend from source (npm 4.2.6 lacks the Worker setup
protocol, so the published dist is skipped automatically).
@BAJJDY BAJJDY closed this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant