前言¶
DeepSeek Harness(下称 DSH)的 Web GUI 默认不带登录,它假设只有 localhost 上有一个用户。一旦把服务绑定到 0.0.0.0——用手机访问、在局域网里共享、或交给小团队使用——同一网络内的任何人都能打开这个页面:读到全部会话、消耗你配置的模型 API key、甚至修改 host 设置。
DSH 的理念是「一切皆插件」,这类能力不需要改动本体。下面介绍的 islibaodong/dsh-login 就是这样一个插件:给 Web GUI 加一道登录墙、一套多账户体系,以及按用户隔离的会话边界,把单用户部署变成可控的多用户部署。
这是什么¶
islibaodong/dsh-login 是 DSH Web GUI 的多用户登录网关插件,维护者为 islibaodong,许可证为 MIT,归类为 admin-security。它由三部分能力组成:登录墙、GUI 内的用户管理、按用户的会话与工作区隔离。用户的添加与管理不需要 CLI,全部在 Web GUI 里完成。
核心功能¶
登录墙¶
页面、静态资源、SPA 路由、API 与 WebSocket 均要求有效会话,未认证访问统一重定向到 /login。也就是说,不只是页面打不开,直接请求 API、建立 WebSocket 同样被挡住。
多账户与用户管理¶
首次访问会显示一次性的「创建管理员账户」页面。之后的新用户由管理员添加:登录后进入 设置 → 用户管理 → 新建用户。
用户管理面板提供最近登录时间、在线会话数,以及重置密码、禁用、移除三种操作。禁用、移除、改密都会立即吊销该用户的在线会话。
dsh-login 自身的设置贡献已按用户区分:管理员看到 设置 → 用户管理,普通用户看到 账户(身份 + 登出)。普通用户不会调用管理员 API,每个用户也都能在设置面板里找到登出入口。
按用户隔离会话与工作区¶
普通用户只能看到和操作自己的会话(包括自己创建的 subagents/forks);他人的会话、消息、工作区一律不可见。凭据、host 设置等管理域对普通用户整体禁止。
管理员是例外:不受隔离,可见全部会话,拥有完整配置权限。
插件还提供 defaultWorkspace:在用户首次访问 /api 时为其自动配置默认工作区。
远程访问:Host 白名单自动学习¶
/api 的 host 信任校验使用一个动态集合:LAN 字面量 + trustedHosts + 自动学习的主机。任何一次成功登录,其 Host 都会写入持久化白名单。因此通过 frp、隧道或局域网 IP 访问 GUI 时,不需要手工编辑 trustedHosts;白名单本身可以在 设置 → 用户管理 中管理。
能力发现与静默拒绝¶
两个配套机制,减少普通用户浏览器里的无意义报错:
- 能力发现:
GET /api/auth/capabilities,需会话认证,客户端据此了解当前会话具备哪些能力; - 静默读拒绝:无权限的读探测返回 204 而不是报错,写操作仍返回 403,该行为可通过 quietDenials 开关。
会话持久化¶
登录会话持久化到 <dataDir>/sessions.json(文件权限 0o600)。进程重启后已有的 cookie 仍然有效,默认 TTL 为 7 天;只有真正的登出、密码修改、用户移除或 TTL 到期才会使其失效。
安装与启用¶
安装是一条命令:
dsh plugin --profile web add github:islibaodong/dsh-login
之所以是 --profile web:DSH 按 profile 目录($DSH_HOME/profiles/<name>)安装插件,而 web 是启动 Web GUI 的那个 profile。如果你用的是自定义 profile,把命令里的 web 换成对应名称即可。
安装时,dsh plugin add 会读取包内声明的 cordis.patch.yml,自动完成三件事:
1、挂载 dsh-login 插件行;
2、禁用 web-runtime 行(dsh-login 接管 frontend-static 的 fallback 位置,并重新提供 webRuntime 服务);
3、禁用自带的 connection 行(dsh-login 挂载自己的身份感知接管,并提供 dist/client.js)。
经过上面的步骤,重启 dsh web 并打开 GUI,首次访问会出现一次性的「创建管理员账户」页面,设置用户名与密码;随后以管理员身份登录,在 设置 → 用户管理 → 新建用户 中添加其他用户。
不需要时,卸载同样是一条命令:
dsh plugin --profile web remove @islibaodong/dsh-login
手动安装(替代方式)¶
如果你希望自己管理 patch 文件,可以在 profile 的 cordis.patch.yml 中添加 insert 行:
- insert:
- id: dsh-login
name: '@islibaodong/dsh-login'
config:
password: DSH_LOGIN_PASSWORD # 凭据引用名,用户存储按 <name>_USERS 命名
distIndex: '' # 留空自动解析前端 dist
dataDir: '' # 留空解析为 <DSH_HOME>/.dsh-login
sessionTtl: 604800 # 会话 TTL,默认 7 天
autoTrustHosts: true # 成功登录的 Host 写入 /api 白名单
enabled: true # 设为 false 可不卸载直接停用
defaultWorkspace: true # 首次 /api 访问时自动配置默认工作区
workspaceRoot: '' # 默认工作区的根目录,留空为 <DSH_HOME>/workspaces
注意:dsh-login 会接管 fallback 位置并重新提供 webRuntime 服务,所以手动安装时除了插入上面的行,还需按仓库 README 的说明禁用 web-runtime 行与自带 connection 行,其余组合不受影响。
从旧版单密码版本升级¶
dsh-login 此前是单密码版本。从旧版升级后,旧的单密码不再能登录任何人,升级后首次访问会引导创建新的管理员账户。
当前状态:开发已暂停¶
仓库 README 明确标注:本仓库的开发已暂停。已交付的功能——登录墙、多账户管理、按用户隔离、远程 web-ui 兼容、能力发现、静默读拒绝——完整可用。未完成的是按角色控制第三方 UI 插件功能(对无权限用户隐藏、不渲染、不发请求),这一项被上游 DSH 的能力阻塞,不是本插件单独能解决的。
具体卡在三处上游限制:
1、DSH 设置面板渲染的是单一全局 section 列表,插件无法在 dsh-login 内按用户显示或隐藏设置 section;
2、DSH WebServer 的路由优先级为 exact-beats-prefix,且没有 pre-routing hook,自行注册精确路由的第三方插件(例如 @linxin666/dsh-pet 注册的 /api/pet/pets、/api/pet/state)无法被 dsh-login 按用户拦截或静默;
3、DSH 客户端运行时会激活所有打包插件,没有按用户的激活门槛,未改造的第三方插件仍会对每个用户触发挂载期探测。
作者在等待上游 DSH 提供 per-identity 的 slot/section 过滤或条件插件激活;届时可以在已交付的能力面之上,实现按角色的功能控制。
适用场景与注意事项¶
适合的场景:
- 把 DSH Web GUI 暴露到局域网,多人共用;
- 通过 frp 或隧道从外部访问自己的 GUI;
- 小团队共用一套服务,各自维护各自的会话与工作区。
使用前注意:
1、插件以当前 dsh 进程的权限运行,安装任何第三方插件前都应检查其源码与许可证。dsh-login 的许可证为 MIT,源码在 GitHub 公开。
2、普通用户的能力边界是明确的:可以正常聊天——创建、打开、继续自己的会话,运行 subagents,管理自己工作区的内容;其余操作(读他人会话、凭据、插件/预设/host 设置、模型 key 管理)都会被拒绝。
3、开发已暂停,且按角色的第三方插件功能控制依赖上游进展,选用前请把这两点纳入评估。
小结¶
dsh-login 用一条安装命令,给 DSH Web GUI 补上了默认缺位的登录与多用户能力:登录墙挡住未认证访问,管理员在 GUI 内完成账户管理,普通用户之间会话互不可见,重启后登录态依然保留。对需要把 GUI 开放到局域网或远程访问的使用者,这是补齐这块短板的直接做法。
- 目录页:https://www.skillhub.cn/plugins/islibaodong/dsh-login
- GitHub 仓库:https://github.com/islibaodong/dsh-login
skillhub.cn 是社区维护的插件目录,与 DeepSeek、幻方无官方从属关系。