dsh-multiuser-keys:多用户共用一台 Harness 时,每人用自己的 Provider API Key

前言

在公司或团队里,常见做法是把一台 DeepSeek Harness(DSH)部署成单实例 Web 服务,让多人通过浏览器共用。模型调用往往要对接公司网关或各家云厂商,凭据通常写在服务器环境变量或 Harness 配置里——结果是额度、计费都落在同一套 Key 上,个人很难「用自己的账户、自己的额度」。

下面介绍社区插件 dsh-multiuser-keys(包名 @local/dsh-multiuser-keys,维护者 az13js,分类 admin-security)。它让管理员指定「哪些 provider 需要用户自备 Key」,用户在浏览器里填写并保存;Key 只留在用户本机,随请求进入服务器内存参与解析,不落盘。未列入映射的 provider 仍走 Harness 默认凭据,便于以后改为公司统一发额度。

这是什么

dsh-multiuser-keys 面向「同一台 Harness 被多人共用」的场景:每人用自己的 provider API Key,消耗各自账户额度。

插件以当前 DSH 进程权限运行;安装前请自行阅读源码与仓库中的许可证信息。社区目录为独立站点,与 DeepSeek / 幻方无官方从属关系。

工作原理(摘要)

  1. 浏览器:Key 保存在 localStorage;同源 /api 请求携带 header x-dsh-user-keys(内容为 base64url 编码的 JSON),不发给第三方域名。
  2. 服务器 Host 半(index.js):在 HTTP 层读取 header,用 AsyncLocalStorage 记录本次请求的 Key 环;包装 ctx.credentials.resolve(),仅拦截管理员配置的凭据引用(apiKeyEnv 名),其余委托原生实现。
  3. 服务器 Client 半(client.js):在「设置 → 我的 API Key」提供配置页。
  4. 内存与生命周期:Key 在服务器上仅存于进程内存(会话绑定最多 512 条 + 最近活动 Key 环,默认 30 分钟内有效)。重启或更新后,用户浏览器下次请求会自动带上 Key,无需额外操作。

核心功能

  • 管理员配置哪些 provider(如 llm-pi-ai 路由名)需要用户自备 Key;未配置的 provider 行为与未装插件时一致。
  • 用户侧设置页显示已映射 provider 的「已配置 / 未配置」,Key 输入默认掩码;保存后对下一次请求生效,清除则回退服务器默认凭据。
  • 不新增 HTTP 端点,复用既有 /api;与 --trusted-host、Nginx proxy_pass 透传请求头的用法兼容(注意勿在网关日志中记录含 Key 的请求头)。
  • 可选配置:recentRingWindowMs、header、source、logResolutions 等(见管理员配置一节)。

安装与启用

前置:目标机器上有 pnpm(Harness 插件管理器需要;仅有 corepack 时可 corepack enable pnpm,或使用 exec corepack pnpm "$@" 的 shim)。

把插件目录放到服务器任意位置(例如 /opt/dsh-plugins/dsh-multiuser-keys),然后二选一:

方式一(推荐):在 GUI 插件页安装,或由 Agent 调用 plugin_manager install_bundle,target 传目录绝对路径。

方式二:命令行等价操作:

dsh plugin --profile web add /opt/dsh-plugins/dsh-multiuser-keys

并把 "@local/dsh-multiuser-keys" 追加到 ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 数组。

也可将包发布到公司私有 registry 后按包名安装。README 说明本插件无安装脚本、无 npm 依赖,安装不会触发 build script。

Kubernetes:$DSH_HOME(默认 ~/.dsh)下 profiles/web/ 须在镜像构建阶段装好插件,避免 Pod 重建后插件丢失。示例片段:

COPY dsh-multiuser-keys /opt/dsh-plugins/dsh-multiuser-keys
RUN dsh plugin --profile web add /opt/dsh-plugins/dsh-multiuser-keys \
 && node -e "const f='/root/.dsh/profiles/web/package.json',fs=require('fs'),p=require(f);p.dsh.profile.bundles.includes('@local/dsh-multiuser-keys')||p.dsh.profile.bundles.push('@local/dsh-multiuser-keys');fs.writeFileSync(f,JSON.stringify(p,null,2))"

管理员配置

任选一种方式。

A. 写在 profile patch 的插件行(完整示例见仓库 config.example.yml):

- id: multiuser-keys
  name: "@local/dsh-multiuser-keys"
  config:
    providers:
      - provider: company-gateway
        label: 公司大模型网关
      # - provider: openrouter
      #   ref: OPENROUTER_API_KEY

B. 独立 JSON 文件(适合 ConfigMap 挂载):

- id: multiuser-keys
  name: "@local/dsh-multiuser-keys"
  config:
    configFile: /etc/dsh/multiuser-keys.json
{ "providers": [ { "provider": "company-gateway", "label": "公司大模型网关" } ] }

ref 可省略:插件会从 settings 读取该 provider 的 apiKeyEnv;读不到的 provider 会告警并跳过。改完配置需刷新浏览器页面,provider 目录随首页 HTML 下发。

典型用法(用户)

  1. 打开 Harness Web:设置 → 我的 API Key(英文界面为 My API keys)。
  2. 对每个已映射的 provider 粘贴自己的 Key → 保存。
  3. 发一条对话或任务,确认走个人 Key 的计费路径(需在管理员侧完成 provider 映射并刷新页面)。

自检(Host 侧):

node test/host.test.mjs

卸载:插件管理器 remove_bundle @local/dsh-multiuser-keys;浏览器中的 Key 清站点数据即可。

适用场景与注意

适合:单实例容器或内网 Harness,多人 Web 共用,且希望部分模型路由由各人自带 Key、其余仍用服务器统一凭据。

已知限制(摘自 README):

  1. 同一会话被两人同时用时,会话绑定以最后一次请求为准,无用户级会话隔离——建议各自独立会话。
  2. 桌面端 IPC、ACP/CLI 等非 Web 通道无法注入浏览器 Key,行为等同未配置。
  3. 无会话上下文的后台任务在 recentRingWindowMs 内可能使用「最近活跃用户」的 Key,超出则回退默认凭据。
  4. Models 设置页仍反映服务器端凭据状态;用户 Key 状态以本插件设置页为准。
  5. Key 信任边界与同源页面相同:能在该站点执行脚本的主体可读取 localStorage。

README 记载在本机 Harness(0.2.0-rc.2,web profile)上做过安装与 Host 测试;真实浏览器下的保存、header 往返及映射后的计费路径,需在你的环境中自行点验。

结尾

dsh-multiuser-keys 用「浏览器存 Key + 请求头注入 + 服务端按映射解析凭据」的方式,在不大改 Harness 部署形态的前提下,把部分 provider 的额度拆到个人。若你正在维护多人共用的 DSH,可从目录页与 GitHub 仓库查看说明与 config.example.yml,再按上述步骤安装与配置。

  • 目录页:https://www.skillhub.cn/plugins/az13js/dsh-multiuser-keys
  • GitHub:https://github.com/az13js/dsh-multiuser-keys
羽毛球分组比赛记分
小程序二维码

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

小夜