dsh-webui-auth: Adding Persistent Authentication Gate to DSH WebUI

前言

DeepSeek Harness(DSH)的 WebUI 默认在本机或局域网内监听 HTTP 服务。只要知道地址和端口,未登录的访问者同样可以加载页面、调用 /api、建立 WebSocket。对放在公网反代后面、或多人共用同一台机器的场景,这等于把智能体配置、凭证和会话面完全暴露在网络可达范围内。

社区里常见做法是依赖反向代理层的 Basic Auth,或只在防火墙侧收口;它们要么与 DSH 自身的 Host 信任、Cookie 交换机制脱节,要么无法在同一层同时拦住静态资源、插件 bundle 和 RPC。下面介绍 multidsh 维护的 dsh-webui-auth(npm 包 @multidsh/dsh-webui-auth):在插件层对 WebUI 做传输层强制认证,会话落盘,重启进程不丢登录态;本仓库在 npm 包 dsh-webui-auth@0.3.6 基础上合并 0.3.7 补丁,修复 nginx 等反代强制改写 Host 时登录跳转错误的问题。

这是什么

dsh-webui-auth 是 DSH 的持久化 WebUI 身份认证插件(组合包 bundle)。在「设置 → 身份认证」或首次访问登录页创建账号密码后,未认证的浏览器无法加载 WebUI 任何资源、调用任何接口或建立任何实时连接;认证在 HTTP/传输层执行,不能靠浏览器开发者工具绕过。

维护与发布:multidsh(GitHub 仓库 multidsh/dsh-webui-auth);上游基于 Yuuz12 的 dsh-webui-auth@0.3.6(MIT),许可证与版权声明原样保留。社区目录分类为 admin-security。当前 npm 版本 0.3.7,零额外 npm 依赖。

核心功能

四层路由包装,不改核心源码

认证通过运行时包装 webServer 路由实现,不修改 DSH 核心包源码。大致分工如下:

层 未认证时的行为
WebUI 资源(index.html、/assets/*、SPA 路由) 302 到登录页
/plugins/* 401
/api RPC 401
WebSocket(含 /api/remote.mux 等) 401,拒绝升级

插件每次启动会重做路由包装,并用 2s→10s 重扫捕获晚注册路由。若预期路由包装不完整,setup/configure 会拒绝启用认证(fail-closed),宿主日志与设置页同时报错,避免「开了登录却 /api 裸奔」。

同前缀的顶层 exact 路由(例如 client-hmr 的 /plugins/events)也会被纳入包装,避免匿名读取客户端插件图或长期挂着 SSE。

会话与口令

会话为服务端会话,持久化到磁盘(sessions.jsonl),重启 DSH 不掉线,到期自动失效。浏览器通过 HttpOnly; SameSite=Lax Cookie(dsh_wua_session)携带,前端 JS 无法读取。修改密码会吊销所有其他会话。

与核心浏览器认证协作

DSH 核心 v0.1.2-alpha.2 及以上自带 launch-token 交换的签名 Cookie(dsh-auth-*)。插件登录成功后会引导浏览器到核心的带 token 根 URL 完成 Cookie 交换;/api 在插件会话校验后原样转交核心。浏览器须同时持有插件会话 Cookie 与核心 Cookie。

0.3.7:反代 Host 与登录跳转

部分 nginx 部署会 proxy_set_header Host localhost;,旧逻辑会把登录成功后的跳转 authority 退化成 http://localhost/?token=…。0.3.7 构造跳转 authority 时优先采用 X-Forwarded-Host(严格校验为裸 host[:port]),失败才回退到 Host。

部署侧通常还需要:

  • dsh web --public-url http://web.example.com 决定打印/打开的入口地址;
  • 非回环域名加入信任列表,例如 dsh web --trusted-host web.example.com(等价于 client-connection.trustedHosts),否则核心 /api 与 WebSocket 仍可能按 Host 栅栏拒绝。

WebSocket 在反代/局域网下还需在 DSH 配置里把对外域名加入 client-connection.trustedHosts,否则已登录也可能无法完成 WS 升级。

DSH Desktop 适配

桌面端使用独立 profile desktop。插件 0.3.6 起提供「宿主直连信任桥」:对已被核心认证过的回环宿主直连请求放行,并原样处理核心的 token→cookie 交换(303 + Set-Cookie),避免桌面端因 shell 丢弃 set-cookie 而卡在「Desktop Host authentication failed」。桌面端窗口在传输层无法像浏览器一样落插件会话 Cookie,因此采用 UI 级锁(解锁令牌存 sessionStorage / localStorage,语义见 README)。

DSH Desktop 的 dsh-desktop-* URL 标记在登录跳转中可能丢失;0.3.5 起通过 Cookie dsh_wua_desktop 在文档加载前补投带标记的同源 /,逻辑隔离在 lib/desktop-adapter.js。

安装与启用

前提:机器上可用 pnpm(Node 自带 corepack 时可执行 corepack enable pnpm)。

Web profile(推荐,npm):

npx @deepseek-ai/dsh plugin --profile web add @multidsh/dsh-webui-auth

Web profile(GitHub 源码):

npx @deepseek-ai/dsh plugin --profile web add github:multidsh/dsh-webui-auth

DSH Desktop:

npx @deepseek-ai/dsh plugin --profile desktop add @multidsh/dsh-webui-auth

安装后无需给核心打补丁、不改 node_modules 里的核心包;重启 DSH 即生效。成功启动时宿主日志应出现 [dsh-webui-auth] started, credentials file: ...;若出现 ROUTE GATE INCOMPLETE,认证不会启用。

手动备用方式:将包目录放入 profiles/web/node_modules/@multidsh/,并在对应 profile 的 cordis.patch.yml 的 insert 列表增加插件行(字段见仓库 README)。

典型用法

1、按上一节命令把插件加入 web 或 desktop profile,重启 DSH。

2、浏览器打开 WebUI,按提示在登录页或「设置 → 身份认证」创建账号与密码。

3、若前面有 nginx 反代且改写了 Host,确保配置 X-Forwarded-Host(nginx 常用 proxy_set_header X-Forwarded-Host $host;),并按 README 设置 public-url 与 trusted-host。

4、桌面端安装到 desktop profile 后,日志出现 host carrier bridge active 表示宿主桥就绪;口令管理与审计在设置页仍可用,浏览器访问宿主 WebUI 依旧需要登录。

适用场景与注意

适合谁: 需要给 DSH WebUI 加账号口令、且希望未登录时静态资源与 API 一并拒绝的场景;公网或局域网反代部署、以及使用 DSH Desktop 且希望与宿主 Web 认证策略对齐时,README 中的 Host / trustedHosts / Desktop 桥接说明需要一并阅读。

安全与信任: 插件以当前 DSH 进程权限运行,凭证与会话文件位于 DSH 数据目录;安装前应在 GitHub 仓库 查看源码与 MIT 许可证。社区插件目录 skillhub.cn 与 DeepSeek / 幻方无官方从属关系,安装决策以你方环境为准。

反代旧核心: README 提到在 ≤alpha.1 核心下,已认证请求可能以回环形状转交核心,以便反代部署下使用回环钉死的特权 RPC;具体边界以仓库文档为准。

结尾

dsh-webui-auth 把 WebUI 认证做成可安装的持久化插件:四层路由闸门、磁盘会话、fail-closed 启用策略,并在 multidsh fork 中补上反代 Host 导致的登录跳转问题,同时覆盖 Desktop 宿主桥与 UI 锁。需要进一步了解版本变更时,可查看仓库 CHANGELOG.md。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye