@emdash-cms/auth-atproto 套件為 EmDash 新增了 Atmosphere 帳戶 登入選項。Atmosphere 帳戶是一種可攜式、由使用者擁有的身分,可在 Bluesky 及 AT Protocol 網路中的其他應用程式上使用。使用者使用自己的 handle(例如 alice.bsky.social)登入,並在自己的提供者處進行身分驗證 — EmDash 永遠不會看到密碼。
在以下情況下,這是很好的選擇:
- 你的貢獻者已經擁有 Atmosphere 帳戶。
- 你想限制對組織所控制網域(
*.yourcompany.com)的存取,而無需管理 OAuth 應用程式或邀請。 - 你正在建構屬於更廣泛 Atmosphere 生態的產品,並希望與技術堆疊的其餘部分保持一致的身分。
安裝
安裝提供者套件:
pnpm add @emdash-cms/auth-atproto
將提供者新增到 EmDash 整合中:
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { atproto } from "@emdash-cms/auth-atproto";
export default defineConfig({
server: {
host: "127.0.0.1", // required for local development; see below
},
integrations: [
emdash({
authProviders: [atproto()],
}),
],
});
這樣就足以在登入頁面和設定精靈上顯示 Sign in with Atmosphere。未設定允許清單時,第一個使用者成為 Admin,之後所有人的自助註冊都會關閉 — 請參閱允許清單來開放註冊。
該提供者是一個公開 OAuth 用戶端,並在 /.well-known/atproto-client-metadata.json 提供自己的中繼資料文件,因此僅憑上面的設定即可運作 — 無需設定環境變數、用戶端密鑰或註冊 OAuth 應用程式。
設定存取
atproto() 提供者接受一個允許清單和一個預設角色:
atproto({
allowedDIDs: ["did:plc:abc123..."],
allowedHandles: ["*.example.com", "alice.bsky.social"],
defaultRole: 30, // Author
});
| 選項 | 型別 | 預設值 | 說明 |
|---|---|---|---|
allowedDIDs | string[] | 無 | 精確比對的 DID 允許清單。 |
allowedHandles | string[] | 無 | handle 允許清單。支援開頭的萬用字元(*.example.com)。 |
defaultRole | number | 10(Subscriber) | 指派給第一個使用者之後被允許的使用者的角色。第一個使用者一律是 Admin。 |
完整的角色層級記錄在主身分驗證指南中。
允許清單
如果既沒有設定 allowedDIDs 也沒有設定 allowedHandles,則只有第一個使用者可以註冊。已關聯到 EmDash 使用者的帳戶可以繼續登入,而新帳戶會被拒絕,並傳回 signup_not_allowed。
當至少設定了一個允許清單時,每一次登入(包括現有使用者的登入)都必須與之相符。將現有使用者的 DID 和 handle 從已設定的清單中移除,該帳戶就無法再登入。只要任一個清單相符,使用者就會被允許:
- DID 相符。 使用者穩定的帳戶識別碼與
allowedDIDs中的某個值完全相符。 - handle 相符。 使用者的 handle 與
allowedHandles中的某個項目相符,可以是精確比對,也可以透過開頭帶萬用字元的模式比對(*.example.com符合alice.example.com和bob.team.example.com)。
儘管 handle 是可變的,handle 允許清單仍然是安全的。在透過 handle 相符放行使用者之前,EmDash 會獨立解析該 handle 的 DNS/HTTP 記錄,並驗證它指向的 DID 與提供者宣稱的 DID 相同。行為異常的提供者不能僅僅宣稱自己擁有 you.yourcompany.com。
預設角色
被允許的使用者會獲得你在 defaultRole 中設定的角色。只有第一個使用者 — 即完成設定的使用者 — 會被強制設為 Admin。Atmosphere 帳戶沒有群組/角色對映;如果你需要更細緻的角色,請在使用者首次登入後,在管理後台側邊欄的 Users 頁面中變更該使用者的角色。
設定第一個使用者
當你使用已設定 Atmosphere 提供者的全新網站啟動時,設定精靈會將其作為建立初始管理員帳戶的選項提供。
-
造訪
/_emdash/admin。在 Set up your site 中,輸入網站標題和選填的副標題,然後繼續。 -
在 Create your account 中,輸入要儲存在 EmDash 使用者上的電子郵件地址和選填的姓名。
-
在 Secure your account 中,選擇 Atmosphere,輸入你的 handle(例如
alice.bsky.social),然後繼續。 -
你的帳戶提供者會開啟其授權頁面。使用該提供者支援的方式登入,並核准請求。
-
提供者會將你重新導向回 EmDash。EmDash 會將第一個使用者建立為 Admin,儲存第 2 步中的電子郵件,建立 EmDash 工作階段,並開啟儀表板。
之後的登入從 handle 開始,在帳戶提供者處繼續,並帶著 EmDash 工作階段返回。提供者的 OAuth 狀態和權杖與該 EmDash 工作階段分開儲存,因此 OAuth 回呼可以完成,提供者也可以重新整理自己的工作階段。
本地開發
AT Protocol 的 OAuth 設定檔要求迴路重新導向 URI 使用 IP 字面值(127.0.0.1 或 [::1]),而不是 localhost。EmDash 在產生重新導向 URI 時會透明地將 ://localhost 改寫為 ://127.0.0.1,但這意味著你的開發工作階段也需要從 127.0.0.1 開始 — 否則,在 localhost 上設定的工作階段 cookie,在重新導向將你帶到 127.0.0.1 之後將不可見。
Astro 的開發伺服器使用 Vite,預設繫結到 localhost。請將 Astro 頂層的 server.host 選項設定為迴路 IP:
export default defineConfig({
server: {
host: "127.0.0.1",
},
// ...
});
然後在 http://127.0.0.1:4321/_emdash/admin 開啟,完成整個流程。
正式環境
相同的設定在正式環境中同樣適用。提供者會在以下位址提供自己的用戶端中繼資料:
https://your-site.example.com/.well-known/atproto-client-metadata.json
授權伺服器在登入期間會擷取此 URL,以驗證用戶端的重新導向 URI。請確保你部署的網站 URL 可透過 HTTPS 從公用網際網路存取 — 位於 VPN 之後、僅限內部存取的部署無法完成登入,因為使用者的授權伺服器無法擷取中繼資料文件。
如果你在終止 TLS 的反向代理後面執行 EmDash,請設定 siteUrl,以便 EmDash 建構正確的重新導向 URI。沒有它,請求看起來像 http://internal-host:4321,中繼資料將與授權伺服器看到的不相符。
疑難排解
”Account is not in the allowlist”
你用來登入的 handle 或 DID 不在 allowedDIDs / allowedHandles 中。請檢查萬用字元模式(必須以 *. 開頭),並記住 handle 相符是針對 DNS/HTTP 驗證的 — 如果該 handle 的 DID 記錄目前沒有解析到提供者傳回的同一個 DID,相符就會被拒絕。
“Self-signup is not allowed”
你已成功到達回呼,但沒有設定允許清單,並且你不是第一個使用者。請將該帳戶的 DID 新增到 allowedDIDs,或將其已驗證的 handle 新增到 allowedHandles。電子郵件邀請不會將 Atmosphere DID 關聯到 EmDash 使用者。
登入無錯誤地重新導向到登入頁面
這幾乎總是本地開發中描述的迴路 cookie 問題。在 http://127.0.0.1:4321(設定 server.host: "127.0.0.1" 後)開啟管理面板並重試。
自架 handle 的 handle 解析失敗
提供者透過讓 DNS-over-HTTPS(Cloudflare 的 DoH 端點)與 HTTP /.well-known/atproto-did 查詢相互競速來驗證 handle。自架的 handle 至少需要以下之一:
- 包含
did=<your-did>的_atproto.<handle>DNS TXT 記錄,或 - 包含該 DID 的
https://<handle>/.well-known/atproto-did檔案。
如果兩種方法都失敗,即使底層帳戶有效,handle 相符也會被拒絕。allowedDIDs 中的 DID 不受影響 — 它們是直接比對的。