🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

认证网关 xbzbing/dsh-auth-gateway

DeepSeek Harnessv0.8.7
xbzbing4 天前有提交已提供中文文档扫描:含敏感能力

为 DeepSeek Harness Web 提供认证门禁的 Cordis 插件:密码认证 + TOTP 双因素认证…

43.8/100
综合分
21
GitHub 星标
584
npm 周下载
—/5
用户评分

数据截至 2026/11/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-auth-gateway
npm 源 · dsh-auth-gateway 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么[目录]—
dsh 原生插件 · model
暂无时间戳·判据 →
装得上吗[实装验证]—
曾在 dsh 0.2.1-rc.5 下真实安装成功,但当前 dsh 已更新至 0.2.2-rc.1,本站尚未在新版下复验
L4 · 真实安装等级说明 →
数据截至 2026/10/30·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 4 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-auth-gateway @ 0.8.7
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖要求 >=0.1.5-rc.2 · 最新 0.2.2-rc.1 兼容
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/6 02:29:50

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 56 处,展示前 47 条)
  • 发起网络请求
    client/index.js:1323
    getSettings: async () => (await fetch(BASE + "/login-api/settings")).json(),
  • 发起网络请求
    client/index.js:1324
    getVersion: async () => (await fetch(BASE + "/login-api/version")).json(),
  • 发起网络请求
    client/index.js:1327
    checkForUpdates: async () => (await fetch(BASE + "/login-api/version?refresh=1")).json(),
  • 发起网络请求
    client/index.js:1328
    enableOtp: async () => (await fetch(BASE + "/otp/enable", { method: "POST" })).json(),
  • 发起网络请求
    client/index.js:1329
    verifyOtpSetup: async (otp) => (await fetch(BASE + "/otp/verify-setup", {
  • 发起网络请求
    client/index.js:1334
    disableOtp: async (payload) => (await fetch(BASE + "/otp/disable", {
  • 删除本地文件递归
    scripts/uninstall.mjs:23
    rmSync(dir, { recursive: true, force: true })
  • 读取本地文件
    scripts/reset.mjs:23
    if (!existsSync(passwordFile)) {
  • 删除本地文件
    scripts/reset.mjs:31
    rmSync(passwordFile, { force: true })
  • 写入本地文件
    lib/audit-log.js:157
    await mkdir(this.dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    lib/audit-log.js:158
    await chmod(this.dir, 0o700)
  • 读取本地文件
    lib/audit-log.js:162
    const { mode } = await stat(live)
  • 写入本地文件
    lib/audit-log.js:163
    if ((mode & 0o777) !== 0o600) await chmod(live, 0o600)
  • 读取本地文件
    lib/audit-log.js:205
    names = await readdir(legacyDir)
  • 读取本地文件
    lib/audit-log.js:218
    const st = await stat(src)
  • 读取本地文件
    lib/audit-log.js:229
    if (name === AUDIT_LOG_NAME && !existsSync(join(this.dir, AUDIT_LOG_NAME))) {
  • 读取本地文件
    lib/audit-log.js:237
    if (!existsSync(dest)) break
  • 写入本地文件
    lib/audit-log.js:248
    await chmod(dest, 0o600)
  • 删除本地文件
    lib/audit-log.js:249
    await unlink(src)
  • 写入本地文件
    lib/audit-log.js:315
    await mkdir(this.dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    lib/audit-log.js:316
    await chmod(this.dir, 0o700)
  • 读取本地文件
    lib/audit-log.js:320
    try { size = (await stat(live)).size } catch (err) {
  • 删除本地文件
    lib/audit-log.js:378
    await unlink(live)
  • 删除本地文件
    lib/audit-log.js:418
    await unlink(join(this.dir, name))
  • 读取本地文件
    lib/store.js:23
    return existsSync(passwordFilePath())
  • 写入本地文件
    lib/store.js:58
    writeFileSync(tmp, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 })
  • 写入本地文件
    lib/store.js:59
    renameSync(tmp, target)
  • 读取本地文件
    lib/store.js:65
    const record = JSON.parse(readFileSync(passwordFilePath(), 'utf8'))
  • 读取本地文件
    lib/store.js:75
    const record = JSON.parse(readFileSync(passwordFilePath(), 'utf8'))
  • 读取本地文件
    lib/otp-store.js:30
    return existsSync(otpFilePath())
  • 读取本地文件
    lib/otp-store.js:66
    const st = statSync(path)
  • 读取本地文件
    lib/otp-store.js:70
    const data = JSON.parse(readFileSync(path, 'utf8'))
  • 写入本地文件
    lib/otp-store.js:87
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    lib/otp-store.js:90
    writeFileSync(tmp, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 })
  • 写入本地文件
    lib/otp-store.js:91
    renameSync(tmp, target)
  • 读取本地文件
    lib/otp-store.js:92
    const st = statSync(target)
  • 删除本地文件
    lib/otp-store.js:165
    unlinkSync(otpFilePath())
  • 删除本地文件
    lib/otp-store.js:166
    rmSync(`${otpFilePath()}.tmp`, { force: true })
  • 读取本地文件
    lib/version.js:133
    const raw = JSON.parse(readFileSync(url, 'utf8'))
  • 读取本地文件
    lib/otp-crypto.js:106
    if (existsSync(path)) {
  • 读取本地文件
    lib/otp-crypto.js:107
    const key = readFileSync(path)
  • 写入本地文件
    lib/otp-crypto.js:131
    writeFileSync(path, key, { mode: 0o600 })
  • 发起网络请求
    lib/forward.js:89
    const proxyReq = http.request({
  • 发起网络请求
    lib/forward.js:142
    const proxyReq = http.request({
  • 写入本地文件
    lib/paths.js:22
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    client/build.mjs:59
    writeFileSync(outfile, bundle)
  • 写入本地文件
    client/build.mjs:60
    writeFileSync(join(root, 'client', 'index.js.map'), map)
扫描于 2026/11/5(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

6 张 · 点击查看大图

功能亮点

  • 密码认证
  • TOTP双因素认证
  • 远程访问加固

为 DeepSeek Harness 增加远程访问能力,用密码和 OTP 加固安全。为 DeepSeek Harness 增加安全的远程访问,支持密码认证和 TOTP 双因素认证(2FA)。

v0.8.72026-10-18内容较长已截断
· 主要变更 · publicPaths:匿名放行 dsh 账号登录的 OAuth 回调路径(PR #29,默认 ['/oauth/callback'],设为 [] 关闭)。账号登录的回调由开放平台以跨站顶层导航回跳,浏览器不会携带 SameSite=Strict 的网关会话 Cookie,请求必然匿名到达;落在认证门后 dsh 永远拿不到 code,而平台侧的 authorize_id 已在批准时被消费——之后每次重试只会得到「授权失败 / ALREADY_CONSUMED」。现在网关在认证门之前按精确路径、仅 GET放行该请求,且不铸上游 bearer(与公开静态资产同一口径),Cookie 属性一律不放宽。 · publicPaths 的校验与构造器 fail loud(#30 收尾):保留路径(/ 与其别名 /index.html、/api*、/connect、网关自有页面与已公开静态资产)在加载期报错而不是静默失效;含通配符的条目被拒绝;数组或逗号分隔字符串均可;条目按 basePath 剥离后的路径匹配(与上游注册路径同坐标系),子路径部署不要带前缀。 · 支持 dsh 0.2.1-rc.2:支持区间上界由 0.2.1-alpha.3 抬到 0.2.1-rc.2;同时更正「登录 DeepSeek 账号」Web 入口的版本下界为 0.2.1-alpha.3。 · 认证设置面板的 Cookie 安全下拉改用 dsh 官方 Menu 原语:portal 浮层、选中打勾、外点与 Esc 关闭交给宿主,触发器对齐官方 *selector 样式,避免自造观感;client bundle 已重建,e2e 与契约测试锁定 external require,禁止回退原生 。 · 文档:新增 TROUBLESHOOTING 第 10 节「反代/域名部署下点『登录 DeepSeek 账号』立即报『登录失败』」——上游 loginOrigin 只接受带显式非零端口的回环 http origin,失败发生在 auth_init 之前(与第 9 节的 publicPaths 是两条不同的链),并给出判别特征(startSignIn 立即 200、明文约 174 B、上游 gzip 后 153-157 B、message: "account: protocol");DEPLOYMENT 新增「远程访问下登录 DeepSeek 账号」小节(本机回环入口 / SSH 本地转发 / 其它回环转发 / API Key 四种方式,含端口语义与 cookieSecure 提醒);README 双语在支持版本行后补「已知缺陷」与手动方式简介;致谢新增 @pjj1234 / PR #29。 · 开发脚本:浏览器发现(scripts/chromium.mjs)改为按 playwright 自身语义探测——缓存根由有效环境推导(PLAYWRIGHT_BROWSERS_PATH / INIT_CWD、XDG_CACHE_HOME / HOME / LOCALAPPDATA)、系统浏览器沿 PATH 探测、补入 CfT 的 chrome-headless-shell-* 布局,并新增「对照 playwright 自身 registry」的符合性测试;不再有硬编码路径。截图脚本适配 dsh 0.2.1 并重拍 README 截图。 · 验证 · 单元测试 314/314 全绿(0.8.6 为 295);新增用例覆盖 publicPaths 默认值 / 保留路径拒绝 / 通配符拒绝 / 构造器 fail loud / basePath 下的匿名握手语义 / 面板 cookie-secure 契约 / 浏览器发现 20 例(含符合性测试)。 · npm run check(node --check lib/*.js + 全量测试)通过;npm run build:check 确认 client 产物与源码一致。 · 隔离实例(临时 DSH_HOME + dsh 0.2.1-rc.2 + 本版本):scripts/verify.sh 20/20 全绿(门禁形状、引导改密、会话吊销、login-api 已认证/未认证分支、WebSocket 升级拒绝、改密/登出后旧会话失效)。 · 同一隔离实例上的匿名探针:/ → 302 /login、/login → 200、GET /oauth/callback → 上游 404(放行生效)、POST /oauth/callback 与 /oauth/callback-extra → 302 /login(同路径非 GET、相似路径仍被门禁拦住)、未认证 /api/* → 401、内部 webserver 直连 → 401;/log
v0.8.62026-10-15
· 主要变更 · 支持 dsh 的 --public-url:bundle patch 的 web-runtime 行是整对象替换,此前漏写 publicUrl,操作者声明的 --public-url 会被静默丢弃。该值只影响展示面(启动打印行、默认浏览器 handoff、智能体的运行时上下文、DSH_WEB_URL),dsh 官方 help 明确它 *grants no trust*,不参与路由与鉴权。但丢弃它会让这些面显示内部回环地址,且 handoff 会打开内部端口并带上启动令牌——本地浏览器据此即可铸出 dsh 会话、不经网关密码。修复后 handoff 指向对外 origin,这条本机旁路随之消失。 · 控制台 URL 行优先使用 --public-url:未声明时仍打印回环地址 + LAN 提示,与之前逐字一致,避免控制台与智能体各说一套。 · 支持 dsh 0.2.1-alpha.3:支持区间上界更新为 0.2.1-alpha.3。该版本 BrowserAuth 新增 v2 cookie(带 id 的 API operator,由新增的 /connect 铸造),浏览器会话仍是 v1,网关铸造的正是 v1;新增的 remoteAccess RBAC 只约束非 owner principal,浏览器请求一律以 owner 通过,网关路径不受影响。 · 文档:全部启动示例补上 --no-open,并说明 dsh 的浏览器 handoff 为何会绕过网关密码;SECURITY.md 威胁模型表新增该本机旁路一行;NGINX-DEPLOYMENT 拆开说明 --trusted-host(用不上)与 --public-url(受支持、只影响展示面)。 · e2e 适配 alpha.3 的 UI 改版:设置入口移入侧栏账号菜单,以及新增的「开始使用」账号弹窗(无跳过按钮、遮罩会拦截点击)。 · 验证 · 隔离实例(dsh 0.2.1-alpha.3,临时 DSH_HOME)浏览器 e2e 20/20 全绿,其中一轮在声明 --public-url 的配置下运行——直接验证该值不改变路由与认证。 · curl 门禁 15/15 全绿;单元测试 295/295 全绿(新增 2 个用例锁定控制台 URL 行的两条分支)。 · npm run build:check 产物与源码一致;node --check index.js 通过。 · 打印行两场景实测:无 --public-url 得 dsh web: (LAN: …);声明 --public-url 得 dsh web: (LAN: …)。 · 安全前提复验:内部端口无令牌请求 index 得 401、/api 无 cookie 得 401,且只监听 127.0.0.1。
v0.8.52026-10-09
· 主要变更 · 设置面板「检查更新」的结果从按钮下方移到按钮右侧(同一行显示,窄宽度时自动换行)。 · dsh 支持区间上界更新至 0.2.1-alpha.2(README 中英 + 部署文档),已在隔离实例上实机验证。 · 修正 README 认证说明,与 dsh 0.2.1 源码对齐:替换已失效的旧引用,改用现存原文 “Authentication does not configure TLS, forwarding-header interpretation, or proxies”;保留仍成立的 “There is no logout operation”。 · 部署文档补充 dsh 0.2.1 新 flag 说明:--host 校验收紧为拒绝一切通配地址、接受具体 IP 字面量;--tls-cert / --tls-key 原生 HTTPS 在网关前置时无效(TLS 由前置 nginx 终结)。 · e2e 脚本适配 dsh 0.2.1 预览版说明弹窗(焦点锁定模态框)。 · 验证 · 隔离实例实机 e2e 20/20 全绿、单测 293/293 全绿(dsh 0.2.1-alpha.2)。 · client bundle 重建一致(build:check 通过),node --check lib/*.js 通过。 --- · 要点 · 设置面板「检查更新」的结果从按钮下方移到按钮右侧(同一行显示,窄宽度时自动换行)。 · dsh 支持区间上界更新至 0.2.1-alpha.2(README 中英 + 部署文档),已在隔离实例上实机验证。 · 对照 dsh 0.2.1 源码修正 README 认证说明:失效的旧引用换成仍存在的原文 “Authentication does not configure TLS, forwarding-header interpretation, or proxies”;“There is no logout operation” 仍然成立,保留。 · 部署文档补充 dsh 0.2.1 新 flag 说明:--host 校验收紧为拒绝一切通配地址、接受具体 IP 字面量;--tls-cert / --tls-key 原生 HTTPS 在网关前置时无效(TLS 由前置 nginx 终结)。 · e2e 脚本适配 dsh 0.2.1 预览版说明弹窗(焦点锁定模态框)。 · 验证 · 隔离实例实机 e2e 20/20 全绿、单测 293/293 全绿(dsh 0.2.1-alpha.2)。 · client bundle 重建一致(build:check 通过),node --check lib/*.js 通过。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-auth-gateway 语言:简体中文 | English 为 DeepSeek Harness Web 提供认证门禁的 Cordis 插件:密码认证 + TOTP 双因素认证 + 多层防爆破 + 会话管理 + 登录审计,并在网关层真实拦截每一个请求(HTTP 与 WebSocket),未认证流量无法触及后端。 dsh web 的官方认证只面向本机回环:dsh 0.1.2 起内部 webserver 启用内置浏览器认证(BrowserAuth),但它只是一枚绑定 authority 的 bearer cookie——设计说明写明「没有登出操作」("There is no logout operation"),且「认证不配置 TLS、转发头解释或代理」("Authentication does not configure TLS, forwarding-header interpretation, or proxies")。dsh 0.2.1 虽为直连场景补上了原生 HTTPS(--tls-cert / --tls-key)与具体 IP 绑定(CLI 仅拒绝 0.0.0.0 等通配地址,接受具体地址字面量),但认证层本身依旧没有登出、没有密码 / 多因素、没有防爆破、没有登录审计,也没有为「前面再套一层认证网关」预留任何集成通道。
展开完整文档(README 剩余 1 节)
dsh-auth-gateway

语言:简体中文 | English

为 DeepSeek Harness Web 提供认证门禁的 Cordis 插件:密码认证 + TOTP 双因素认证 + 多层防爆破 + 会话管理 + 登录审计,并在网关层真实拦截每一个请求(HTTP 与 WebSocket),未认证流量无法触及后端。

dsh web 的官方认证只面向本机回环:dsh 0.1.2 起内部 webserver 启用内置浏览器认证(BrowserAuth),但它只是一枚绑定 authority 的 bearer cookie——设计说明写明「没有登出操作」("There is no logout operation"),且「认证不配置 TLS、转发头解释或代理」("Authentication does not configure TLS, forwarding-header interpretation, or proxies")。dsh 0.2.1 虽为直连场景补上了原生 HTTPS(--tls-cert / --tls-key)与具体 IP 绑定(CLI 仅拒绝 0.0.0.0 等通配地址,接受具体地址字面量),但认证层本身依旧没有登出、没有密码 / 多因素、没有防爆破、没有登录审计,也没有为「前面再套一层认证网关」预留任何集成通道。本插件以进程内网关的形态补上这层缺失的远程访问认证:对外端口由网关独占,内部 webserver 由 bundle patch 绑定在本地回环,网关是唯一入口。

本项目支持 0.1.5-rc.2 <= dsh <= 0.2.2-alpha.2,均已实测。

已知缺陷:远程访问(域名 / 反向代理 / 局域网 IP 等非回环 http 入口)下无法登录 DeepSeek 账号——点左下角「登录 DeepSeek 账号」会立即报「登录失败」,其余功能均正常(会话、模型、工具、设置面板等)。根因在 dsh 上游:账号登录要求浏览器 origin 是带显式非零端口的回环 http 地址,而回环地址只在浏览器所在机器上解析——本插件无法在服务端绕过它(远程访问正是本插件提供的形态,所以该限制在这个部署形态下必然遇到)。判别与证据见 docs/zh/TROUBLESHOOTING.md 第 10 节。

手动解决方式(详细操作见 docs/zh/DEPLOYMENT.md 的「远程访问下登录 DeepSeek 账号」一节):

1. 本机回环访问:浏览器与 dsh 同机时,直接打开 http://127.0.0.1:<网关端口>;
2. SSH 本地端口转发:浏览器在异地时执行 ssh -L 8080:127.0.0.1:<网关 listenPort> <部署机>(冒号前是本机端口,任选空闲端口),再浏览 http://127.0.0.1:8080;
3. 其它回环转发方式:任何能把 http://127.0.0.1:<显式端口> 映射到远端网关的隧道 / 端口转发工具(VS Code、kubectl port-forward、gost 等);
4. 改用 API Key 通道:在账号弹窗里点「添加 API Key」,纯域名 / 反代部署下的既定替代方案。

配套 PC 客户端:需要在桌面端集中管理远程 dsh 实例时,可使用 dsh-hub-desktop——Electron 桌面客户端,把本地进程、SSH 隧道、远程 HTTP 直连三种形态的 dsh 实例一站管理。认证对接本插件的网关协议(密码 + TOTP + HttpOnly Cookie 注入,网关五态探测),支持凭据保险库静默登录与实例内插件管理(安装 / 检查升级 / 卸载)。

安装和卸载

安装(从 npm registry)
dsh plugin --profile web add dsh-auth-gateway

启动(对外端口 8080,内部 webserver 自动挪到 8081;--no-open 让 dsh 不自己开浏览器)
dsh web --port 8080 --no-open

卸载(先清凭据,再移除插件) ~/.dsh/profiles/web/node_modules/.bin/dsh-auth-gateway-uninstall
dsh plugin --profile web remove dsh-auth-gateway

- 支持从 GitHub / 本地目录安装,见 docs/zh/INSTALL.md;
- 忘记密码用 dsh-auth-gateway-reset 重置(重启后控制台打印新初始密码);
- 部署指南:docs/zh/DEPLOYMENT.md

功能特性

- 密码认证:首次部署自动生成初始密码(控制台打印,一次性),登录后引导设置个人密码(scrypt 哈希存储),之后每次访问需登录;
- 双因素认证(TOTP):可选启用,兼容 Google Authenticator、Authy、1Password 等主流认证器;含一次性备份代码(scrypt 哈希存储、单次使用),设备丢失时可恢复访问;OTP 密钥以 AES-256-GCM 加密存储(主密钥来自环境变量 DSH_AUTH_GATEWAY_MASTER_KEY 或自动生成的 auth-gateway/otp-master.key),磁盘泄露不再直接暴露第二因素根密钥;
- 真实请求拦截:未认证 /api/ 返回 401、页面类路径 302 到登录页、WebSocket 升级直接拒绝;上游自有的一次性握手路径(publicPaths,默认 /oauth/callback)是唯一的匿名上游握手例外(公开静态资产本就匿名放行)——dsh 账号登录的回调由平台以跨站顶层导航回跳,浏览器必然不带会话 Cookie,见 SECURITY.md;认证通过后请求透明转发(Host/Origin 规范化,兼容内部 trust fence);
- 登录审计:登录成功 / 失败 / 登出 / 改密与暴力破解告警(锁定/限流)均输出审计日志(ctx.logger.info/warn,含来源 IP 与失败原因,不记录任何凭据),并持久化落盘 $DSH_HOME/auth-gateway/log/audit.log(JSONL,按天轮转、保留 90 天),形成完整可审计闭环;
- 多层防爆破:密码失败按来源锁定(默认 5 次/5 分钟)+ 全局速率限制(默认 60 次/分钟)+ OTP/备份码独立限流(默认 10 次/分钟),scrypt 在 libuv 线程池异步执行,登录洪峰不阻塞事件循环;
- 会话管理:内存 256-bit token(30 天),HttpOnly + SameSite=Strict Cookie,修改密码/禁用 OTP 吊销全部会话;
- 合规形态:host-only 插件(零构建、零运行时依赖)+ 可选 client 半(设置面板,源码构建),主体全部经 dsh 官方扩展点(ctx.effect、webServer.tapIndex、ctx.slots);唯有一项记录在案的安全例外——LAN trust(为域名/反代访问下模型设置页可用而对 connection 注册做最小介入,见 TROUBLESHOOTING §1)。

本插件不做的事情

以下需求在"单实例"前提下无法真正实现——它们的前提是进程/OS 强制的执行与存储隔离(独立 OS 账号、容器或沙盒),而本插件只是运行在 dsh 进程内的认证网关,提供不了这层隔离。列出它们是为了明确预期、避免误导:

- 多账号登录 / 多租户:dsh 是单用户工具——一个 Home、一份模型凭据,全部会话与数据(sessions/、workspace/、.credentials.yaml)都以运行 dsh 的 OS 账号权限存放在本地。网关叠加"账号体系"只能区分谁在登录(访问控制 + 审计),无法隔离谁能看到什么:任何通过认证的用户都能经 dsh 的工具执行读取同一 Home 下的全部会话与凭据。没有 OS/容器/沙盒隔离就没有真正的多租户——本插件不做,也无法做到。
- 角色权限限制(用户/管理员):同理,角色只能在网关自身的 HTTP 路由层生效(例如限制网关管理功能),挡不住 dsh 内部的能力面——普通用户一旦通过认证门,即拥有该实例的完整能力(工具执行、会话读写、配置与凭据访问)。需要"普通用户受限"的场景请用 OS 级隔离的多实例部署并自行管理账号。本插件的职责是:认证门禁(谁能进入)+ 拦截与审计(谁做了什么),不承担、也无法承担授权与隔离模型。

工作原理

flowchart LR
B[浏览器] --> G["dsh-auth-gateway 网关对外端口 · 运行在 dsh 进程内"]
G --> C{"认证检查会话表 O(1)"}
C -->|未认证| U["/api/ → 401页面 → 302 /loginWS 升级 → 拒绝"]
C -->|未通过 2FA| O["/otp/verify"]
C -->|已认证| F["转发Host/Origin 改写为回环"]
F --> W["dsh webserver127.0.0.1:内部端口"]

- 网关生命周期与 dsh 绑定:随 dsh 启动/退出,无独立进程;
- bundle patch 将 webserver 移到回环端口(对外 = --port,内部 = 对外 + 1),远程无法绕过网关直连后端;
- 网关在 DSH 的 __ModuleLoader__ 加载 connection 模块时、Settings 等消费者启动前建立客户端 loopback trust——这是唯一记录在案的安全例外(仅拦截 connection 注册,其他插件原样通过);该兼容层不替代登录、HTTP/WebSocket 门禁或服务端 fence,详见 TROUBLESHOOTING §1;
- 认证状态机:首次部署 → 初始密码登录 → 引导(设置个人密码)→ 登录 →(可选)OTP 验证 → 会话;未完成引导或 2FA 的会话仅能访问对应验证端点。

界面预览

引导页(初始密码登录后)登录(含 2FA 验证码)

2FA 登录成功 OTP 设置(QR 码)

设置菜单(含「认证设置」入口)认证设置面板

快速开始

1. 启动 dsh web:首次部署会自动生成初始密码,并打印在控制台(醒目提示块);请复制备用;
2. 打开 Web UI,用初始密码登录——会进入引导页:设置你自己的访问密码(至少 8 位,包含大小写字母或特殊字符;强制,设置完成前所有功能不可用);初始密码是一次性凭据,设置后自动失效;
3. 登录后可访问 /otp/setup 启用 TOTP(扫码或手动输入密钥,输入验证码确认;同时生成备份代码,请妥善保存);
4. 已启用 OTP 后,登录需密码 + 验证码(或备份代码);
5. 修改密码:访问 /login(已登录时显示改密表单),或经「认证设置」面板。

配置

以下字段是 bundle patch / profile patch 中 dsh-auth-gateway 行的 config(Standard Schema 校验):

| 字段 | 默认 | 含义 |
| listenHost / listenPort | 0.0.0.0 / 3080 | 网关对外监听地址与端口 |
| upstreamHost / upstreamPort | 127.0.0.1 / 3081 | 内部 webserver 地址与端口 |
| basePath | / | 反向代理子路径前缀(如 /dsh);默认 /(根路径)。字符集限 A-Za-z0-9._~/-,拒绝 ..、//、引号、空白、尖括号(该值会内嵌进页面脚本与链接,故按白名单校验;不合规配置会在加载时被拒绝)。子路径部署时在部署方 profile patch 中配置,不随插件分发 |
| cookieSecure | auto | 会话 Cookie 是否携带 Secure 属性。auto:请求经 TLS(反向代理透传 X-Forwarded-Proto: https)时自动附加;true:强制附加;false:显式关闭。纯 HTTP 下强制开启会让浏览器拒绝 Cookie。面板可直接修改:覆盖值持久化于凭据记录,优先于部署配置,直至恢复 |
| publicPaths | ['/oauth/callback'] | 匿名可达的上游握手路径(精确匹配、仅 GET)。默认值就是 dsh 账号登录的回调:平台以跨站顶层导航回跳过来,浏览器不会带上网关会话 Cookie,落在门后该功能就永久不可用。只接受精确绝对路径(不接受通配符、查询串),字符集同 basePath(A-Za-z0-9._~/-);数组或逗号分隔字符串均可,重复项自动去重;保留路径(/ 与其别名 /index.html、/api*、/connect、网关自有页面与已公开静态资产)会在加载期被拒绝。设为 [] 关闭放行。条目按 basePath 剥离后的路径匹配(与上游注册路径同坐标系),子路径部署不要带 basePath 前缀。取舍与边界见 SECURITY.md;该项只影响回调那一段——非回环 origin(域名 / 反代)下账号登录在发起阶段即被上游拒绝(account: protocol),与本项取值无关,见 TROUBLESHOOTING §10 |
| minPasswordLength | 8 | 密码最小长度(4–128) |
| requireMixedCase / requireSpecial | true / true | 密码复杂度:大小写混合或特殊字符二选一满足 |
| maxLoginFailures / lockMinutes | 5 / 5 | 密码失败锁定阈值与时长 |
| maxGlobalAuthAttemptsPerMinute | 60 | 全局登录尝试速率上限 |
| maxOtpAttemptsPerMinute | 10 | 单来源 OTP/备份码验证速率上限 |
| otpIssuer / otpPeriod / otpDigits / otpWindow | dsh-auth-gateway / 30 / 6 / 1 | TOTP 参数(显示名、周期、位数、窗口) |
| backupCodeCount / backupCodeLength | 10 / 8 | 备份代码数量与长度 |
| updateCheck | false | 打开「认证设置 → 关于」时自动检查新版本。默认关闭:全新安装不发起任何对外请求。置 true 后在面板打开时自动查询一次公共 npm registry 的 latest(本插件唯一的对外请求,成功缓存 6h / 失败 15min,超时 3s,不含任何凭据)。无论此项如何,面板上的「检查更新」按钮都可手动发起一次检查 |

安全模型

认证状态变更(启用/禁用 OTP、修改密码)均要求完整验证:2FA 激活时禁用 OTP 需当前密码 + 验证码或备份代码;未完成 2FA 的会话不能访问敏感端点。OTP 验证防重放(记录已接受时间步)、防伪造(x-forwarded-for 不计入来源)。OTP 密钥在落盘前以 AES-256-GCM 密封,读取需主密钥——默认自动生成 auth-gateway/otp-master.key(0600),也可经环境变量 DSH_AUTH_GATEWAY_MASTER_KEY(hex/base64,32 字节)注入以隔离磁盘泄露。登录审计只记录事件种类、来源 IP 与失败原因,不落任何凭据。完整威胁模型、已知限制与恢复路径见 docs/zh/SECURITY.md。

文档

| 文档 | 内容 |
| docs/zh/INSTALL.md(English) | 安装、更新、卸载、凭据重置的完整操作步骤 |
| docs/zh/NGINX-DEPLOYMENT.md(English) | 配合 nginx 部署:裸金属直连 / 子域名 / 子路径 / Docker nginx 容器四种拓扑与配置示例 |
| docs/zh/SECURITY.md(English) | 威胁模型、OTP 安全设计、已知限制与恢复路径 |
| docs/zh/DEPLOYMENT.md(English) | 端口与监听、LAN 部署、HTTPS 建议、nginx 反向代理、故障排查 |
| docs/zh/TROUBLESHOOTING.md(English) | 实机故障案例:域名下模型页不可用、原生依赖构建被拦、bundle 加载失败、版本线凭据格式、跨境超时优化 |
| docs/zh/TESTING.md(English) | 单元测试、端到端(Playwright)、API/WebSocket 门禁验证 |
| docs/DEVELOPMENT.md(English) | 架构说明、构建、开发统计 |

致谢

- @adra2n — 实现 OTP 双因素认证(PR #1),并添加 OTP 密钥 AES-256-GCM 静态加密存储与解密路径错误分类(PR #6);
- @meowtech — 报告并初步实现了 dsh 新版本(rc8+ 配置平面收归 loopback)下 LAN 浏览器设置不可用问题的修复(PR #7);该实现(loader 包装 + provide 劫持)随后被证实会破坏共存插件,本仓库已改用最小介入方案重写。
- @LuckVd — 修复 dsh ≥ 0.1.2 上游浏览器认证(BrowserAuth)导致的转发 401(PR #12):经官方 credentials 通道读取密钥并为回环一跳铸造同构 cookie,经评审补齐官方通道读取、轮换即时重铸、部署清单与双语文档后合入。
- @pjj1234 — 实现 dsh 账号登录「OAuth 回调路径匿名放行」(PR #29):新增 publicPaths 配置(默认放行 GET /oauth/callback),平台跨站回跳的回调不再被认证门挡下,修掉「账号登录停在『等待登录』、之后平台一直返回『授权失败』(ALREADY_CONSUMED)」(见 docs/zh/TROUBLESHOOTING.md 第 9 节);合入时由本仓库补全 basePath 匹配语义与「不铸上游 bearer」的测试和文档。

验证概览

- 单元与契约测试:npm test(覆盖 basePath 路由/重定向/转发、PWA 元数据放行、登录审计、审计日志轮转/清理、OTP 安全回归、client 契约、patch 端口推导)
- 部署流水线:npm run deploy(语法检查 → 全量测试 → 同步到 DSH 安装目录 → 安装后验证)
- 实机端到端:node scripts/e2e.mjs(Playwright,登录/2FA/改密全流程)
- 门禁验证:./scripts/verify.sh(curl,401/302/WS 拒绝/锁定)

详见 docs/zh/TESTING.md。

Model Experience

None,本包是浏览器与内部 dsh webserver 之间的认证载体,不会进入任何模型请求。

KV Cache effect

None;本包既不组装也不发送 provider 请求。

License

MIT
预览分享卡片长什么样 ↓xbzbing/dsh-auth-gateway
分享 · DeepSeek Harness Hub
xbzbing/dsh-auth-gateway

为 DeepSeek Harness Web 提供认证门禁的 Cordis 插件:密码认证 + TOTP 双因素认证…

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部