lloydzhou/dsh-feishu-oauth:給 DSH 接上飛書 OAuth 登錄

前言

DSH(DeepSeek Harness)默認對匿名訪問開放:打開首頁就能進入會話,同一個進程的 owner 權限沒有按人切分。把它掛到內網或團隊環境裏時,問題就出現了——誰登錄過、誰還在用,只能去看進程日誌;泄露出去的訪問地址,任何能打開頁面的人都能用。社區裏已有的做法通常是再寫一個獨立的登錄中間件,或者在前面掛一層反代做鑑權,結果要麼和 DSH 的原生會話脫節,要麼要多維護一個組件。

下面介紹 lloydzhou/dsh-feishu-oauth。它由 lloydzhou 維護,分類 admin-security,把飛書 OAuth 接進 DSH 的原生認證流程:登錄成功後直接複用 DSH 自己的會話 Cookie,插件既不修改核心,也不自行簽發 Cookie。也就是說,登出、會話有效期、token 恢復仍由 DSH 原生機制負責,插件只是替換了入口那一步。

需要注意的前提:這個插件不是多用戶權限系統。所有能用飛書應用登錄的人,拿到的都是同一個 DSH owner 的完整權限,沒有獨立賬戶、用戶或租戶白名單、逐用戶審計或撤銷機制。README 明確寫了「僅供可信人員共享使用」,人員範圍需要靠飛書應用的可用範圍來限制。

一、它解決什麼問題,以及它的邊界

插件做的事情只有一件事:把 DSH 的入口從「匿名直接進」換成「飛書授權後再進」。

具體能力如下:

  • 匿名訪問 / 顯示一張「DSH × 飛書登錄」卡片,提供授權登錄按鈕,以及原生 token URL 的登錄提示。卡片支持中英文、窄屏和系統深色模式,不加載任何外部字體、圖片或腳本。
  • 登錄成功後仍停留在 / 顯示 DSH 頁面,地址欄不會跳到別處。成功回調用零延遲的 meta refresh 返回同源 /,不需要用戶再點一次確認,同時結束跨站重定向鏈,以兼容原生 SameSite=Strict Cookie。
  • /?token=... 作爲恢復入口,始終交給原生認證處理。
  • API 和 WebSocket 的鑑權不受影響,繼續走原生認證。
  • 登錄頁樣式通過固定 CSP 哈希授權,不依賴運行時引入的外部資源。

邊界也要說清楚:

  • 飛書撤權、用戶退出或關閉插件,都不會讓已經簽發的 DSH Cookie 失效,其有效期由原生會話管理。README 建議保留原生 token 恢復方式,並明確不要把這個插件當成多用戶權限系統。
  • OAuth 關閉或應用憑據缺失時,插件不註冊登錄路由,行爲回退到原生入口。
  • 保存配置成功,不等於飛書憑據或回調登記有效;README 沒有承諾保存後一定可用。

二、安裝與啓用

環境要求:Node.js >=24.9.0,以及提供 webServer.readResource()、connection.browserPeer 和原生認證接口的 DSH。清單聲明的 DSH 版本下限是 >=0.2.1-rc.3,但 README 同時說明不保證較舊版本具備這些 API,作者用提取的 0.2.2-rc.1 原生模塊做過兼容測試,這不等於所有版本或真實飛書端到端驗證通過。

安裝命令來自 README 原文,需要在插件源碼目錄內執行:

git clone https://github.com/lloydzhou/dsh-feishu-oauth.git
cd dsh-feishu-oauth
npm ci
npm run build:client
dsh plugin --profile web add .

逐步說明:

  1. npm ci 按鎖文件安裝依賴,esbuild 固定版本並由鎖文件鎖定。
  2. npm run build:client 調用 scripts/build-client.mjs,把 src/client/index.js 打包成瀏覽器產物 dist/client.js。npm 包只包含服務端源碼、瀏覽器產物、語言 JSON、DSH patch 和說明文檔,不包含客戶端源碼、構建腳本和測試,所以發佈前需要先構建。
  3. dsh plugin --profile web add . 裝載 plugin bundle,並順帶應用清單裏的 cordis.patch.yml。

裝完之後還要做三件事:

  1. 在 Plugins 頁面啓用本插件 bundle。注意配置頁面裏的「啓用飛書登錄」默認關閉,它與 bundle 的總開關是兩回事。
  2. 使用 DSH 啓動時打印的原生 token URL 登錄,然後打開 Plugins → 已安裝插件 → 本插件的配置頁面。
  3. 在飛書開放平臺應用裏限定可信人員的可用範圍,並登記卡片上顯示的精確回調地址:瀏覽器當前 origin 加 /auth/feishu/callback。

package.json 裏的幾個關鍵聲明:

{
  "name": "dsh-feishu-oauth",
  "version": "0.2.2-rc.2",
  "description": "Feishu OAuth login for DeepSeek Harness using native session cookies",
  "license": "MIT",
  "engines": { "node": ">=24.9.0", "dsh": ">=0.2.1-rc.3" }
}

三、配置項與憑據處理

當前版本提供的配置字段只有三個:

字段 默認值 說明
enabled false 啓用 OAuth 路由
appId 空 飛書 App ID
appSecret 空 原始 App Secret;讀取時脫敏,表單留空表示保留現值

用法上的幾個細節,值得在動手前知道:

  • 輸入的是 App ID 和 App Secret 的原始值,不是環境變量名。
  • 首次配置必須填寫 Secret;之後密碼框留空就表示保留現有值。
  • 密碼框始終以空白載入,保存成功後清空,界面不會告訴你 Secret 到底有沒有配好。
  • 保存成功或出現配置衝突之後,需要重新載入表單再編輯。

安全方面有兩個明確的提醒,README 用了加粗強調:

  • 脫敏和密碼遮罩不等於加密。App Secret 以明文存儲在本機 profile 配置裏,需要保護配置文件及其備份。
  • 允許以 HTTP 訪問 DSH,但瀏覽器提交設置時的 App Secret、原生登錄憑據和會話流量均沒有傳輸加密。飛書 provider 請求始終使用 HTTPS,這不保護瀏覽器到 DSH 的 HTTP 鏈路。README 建議使用原生 HTTPS,並說明不支持「HTTPS 在反向代理終止、DSH 仍監聽 HTTP」的部署。訪問地址還必須滿足原生 Connection 信任規則,Host 保持不變,並與飛書登記的回調地址一致。

四、登錄與恢復流程

走一遍完整路徑:

  1. 匿名打開 /,看到登錄卡片,點授權登錄按鈕。
  2. 跳轉飛書授權端點,授權後回到 /auth/feishu/callback。
  3. 成功回調用零延遲 meta refresh 回同源 /,此時原生 Cookie 已寫入,用戶看到 DSH 界面,地址欄仍是 /。
  4. 後續請求由原生認證接管,插件不再介入。

失敗或恢復路徑:

  • 訪問 /index.html 在匿名狀態下可能拿到原生 401,應該回到 / 登錄。
  • 帶 ?token=... 的訪問始終交給原生認證,這是恢復入口。
  • OAuth 關閉或憑據缺失時不註冊登錄路由,登錄頁不會出現。

相關配置變更時(開啓、關閉、改憑據)插件會撤下 OAuth 路由、取消正在等待的登錄請求,清理之後重新掛載,不影響原生入口。關閉或卸載插件也回到原生入口。

設置集成在捕獲到激活或清理異常時會記錄一條固定脫敏警告;README 同時提醒,並非所有缺失或錯誤配置都會產生警告,不要僅靠有沒有警告來判斷配置狀態。

五、保護措施與已知限制

插件在內存裏做了幾道限制,但要正確解讀它們:

  • state 單次使用、綁定瀏覽器,有效期 300 秒,最多保留 256 個待處理 state;最多同時進行 16 個 provider 交換流程。
  • 這些是單進程容量限制,不是按 IP 限流,也不是 DoS 防護。換成多進程部署時,這套限制不在全局生效。
  • state 只在進程內存中保存,進程退出或配置更新會使待登錄失效;同一瀏覽器發起新登錄會覆蓋舊的臨時綁定。
  • 繞過 Connection 的自定義 listener 不在保護範圍內。

協議和傳輸上的措施:

  • 使用 S256 PKCE,provider 地址爲固定 HTTPS,禁止跟隨 provider 重定向,設置了請求超時和響應大小限制。
  • 臨時 Cookie 是 HttpOnly/SameSite=Lax,HTTPS 下帶 Secure。
  • 原生啓動 token 不進入頁面、不進入瀏覽器重定向、不發往外部 HTTP 請求、不寫日誌;插件也不讀取簽名密鑰。
  • 錯誤只包含固定階段 TOKEN、USERINFO 或 NATIVE_COOKIE,以及已收到的 HTTP 狀態碼和飛書數字錯誤碼,不回顯 provider 返回正文或憑據。

兩個常見故障碼的含義:

  • TOKEN/HTTP_400/CODE_20002 表示飛書拒絕應用憑據。
  • 只有 TOKEN 階段出現、沒有 HTTP 狀態,表示未收到 token 接口響應頭。

README 建議的排查方式:處理完問題後從首頁重新登錄,不要刷新已經消耗掉授權碼的回調頁。

六、飛書協議實現的落點

插件採用授權碼 + PKCE,並保留 S256 challenge 與 verifier,不自動降級,也不重試已使用過的授權碼。

  • 授權端點:https://accounts.feishu.cn/open-apis/authen/v1/authorize
  • 換取 token:https://open.feishu.cn/open-apis/authen/v2/oauth/token,按飛書文檔中的 PKCE 配對說明,通過 JSON 請求體換取。
  • 飛書錯誤碼 20049 表示 PKCE 校驗失敗。

有一點要留意:飛書 v2 token 接口被官方標爲歷史版本,文檔提供了 v3 遷移說明。README 的說明是遷移 v3 之前需要驗證授權端點的 PKCE 兼容性,升級飛書側能力前要先確認新端點是否仍支持 PKCE。

七、開發與驗證

插件以 npm 包形式發佈,想本地改一遍再驗證,可以按下面的順序跑:

npm ci
npm run build:client
npm run check
npm test
npm pack --dry-run --ignore-scripts
  • npm run check 用 node --check 逐個檢查服務端 ESM 源碼、dist/client.js、客戶端源碼和構建腳本。
  • npm test 執行 node --test test/*.test.js,跑單元測試,以及可選的原生模塊兼容測試。
  • npm pack --dry-run --ignore-scripts 用來覈對 npm 包裏實際包含哪些文件。

目錄結構:

src/server/   插件入口、OAuth、登錄頁面及設置生命週期
src/client/   配置卡片與表單邏輯源碼
dist/client.js 瀏覽器 bundle(生成並提交)
scripts/      客戶端構建腳本
test/         單元測試及可選的原生模塊兼容測試
locale/       對外導出的中英文 JSON

package.json 的 files 字段列出了發佈內容:src/server、dist/client.js、locale、cordis.patch.yml、README、LICENSE、SECURITY.md、SETTINGS-INTEGRATION.md、ASSET-ATTRIBUTION.md。公開導出保持爲 .、./client、./locale/*.json 和 ./package.json。CI 會在重建瀏覽器產物後檢查差異。

客戶端側還有兩點要留意:客戶端依賴 @deepseek-ai/dsh-client-locale、@deepseek-ai/dsh-client-ui-settings、@deepseek-ai/dsh-client-ui-plugin-manager 三個包,由 manifest 的 client.inject 聲明注入;插件對 DSH 的改動寫在 cordis.patch.yml 裏,升級 DSH 後需要檢查 patch 是否仍然適用。README 明確說模擬測試和提取模塊測試不等於真實瀏覽器或飛書授權往返驗收,升級 DSH 後應該重新驗證。

安全漏洞按 SECURITY.md 私密報告,不要在公開 issue 中提交憑據。

八、適合誰,以及動手前要檢查什麼

適合這類部署:DSH 跑在內網或團隊環境,使用者是一批已知且可信的成員,都在同一個飛書組織里,你希望他們用已有的飛書賬號登錄,而不是每個人單獨發賬號密碼。此時用飛書應用的可用範圍做人員篩選,是這套方案的前提,也是唯一的權限邊界。

不太適合這類場景:

  • 需要逐用戶權限、審計或撤銷能力。這套方案給所有登錄者同一個 owner 權限,撤權只能通過飛書側終止人員訪問,已簽發的 DSH Cookie 不會自動失效。
  • 需要跨多個租戶或組織隔離成員。插件沒有租戶概念。
  • 對傳輸加密有合規要求,但只能提供瀏覽器到 DSH 的 HTTP 鏈路。README 建議使用原生 HTTPS,不支持反向代理終止 HTTPS、DSH 仍監聽 HTTP 的部署。

動手前建議做這三件事:

  1. 讀一遍源碼,尤其是 src/server/oauth.js、src/server/settings.js 和 cordis.patch.yml,確認插件改了什麼、有沒有超出「登錄入口替換」的範圍。許可證是 MIT,許可證文本見倉庫 LICENSE 文件。
  2. 確認 DSH 版本滿足 >=0.2.1-rc.3,並實測所需的原生 API 存在。清單聲明的下限不保證舊版本具備這些能力。
  3. 確認回調地址與飛書應用登記一致,並且網絡出口能讓瀏覽器訪問到這個精確地址。

結語

dsh-feishu-oauth 的價值不在於做了一套複雜的賬號系統,而是用最小的改動把 DSH 的登錄入口接到飛書 OAuth 上,會話狀態仍然交給原生機制管理,需要自己維護的東西少。它的代價也很明確:不提供按用戶區分的權限、審計和撤銷。理解這一點,才能判斷它放進自己的部署裏是否合適。

相關鏈接:

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

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

小夜