EmDash 使用通行密鑰驗證作為主要登入方式。通行密鑰可防釣魚、不需要密碼,且可透過瀏覽器或密碼管理工具跨裝置使用。
對於 Cloudflare 部署,你可以選擇使用 Cloudflare Access 作為替代驗證提供者。
運作方式
通行密鑰使用 WebAuthn——一種建立公開金鑰憑證的網頁標準,憑證儲存在你的裝置上或透過密碼管理工具同步。登入時,你的裝置會證明持有該憑證,而不會透過網路傳送密碼。
通行密鑰驗證的優點:
- 無需記憶或外洩的密碼
- 防釣魚 — 憑證綁定到你網站的網域
- 跨裝置同步 — 支援 iCloud 鑰匙圈、Google 密碼管理工具、1Password 等
- 快速登入 — 一次觸控即可透過生物辨識或 PIN
首位使用者設定
第一次存取管理後台時,設定精靈會引導你建立管理員帳號。
-
前往
http://localhost:4321/_emdash/admin -
你會被重新導向設定精靈。輸入:
- Site Title — 網站名稱
- Tagline — 簡短描述
- Admin Email — 你的電子郵件
-
按 Create Site 以註冊通行密鑰
-
瀏覽器會提示你建立通行密鑰:
- macOS:Touch ID、裝置密碼或安全金鑰
- Windows:Windows Hello 或安全金鑰
- 行動裝置:Face ID、指紋或 PIN
-
通行密鑰註冊完成後,你就會登入並被導向管理儀表板。
登入
設定完成後,返回管理後台會觸發通行密鑰驗證:
-
造訪
/_emdash/admin -
如果尚未登入,你會看到登入頁面
-
按 Sign in 進行驗證
-
瀏覽器會提示你使用通行密鑰(生物辨識、PIN 或安全金鑰)
-
驗證後,你會被導向管理儀表板
魔法連結備援
如果無法使用通行密鑰(例如遺失裝置),魔法連結提供替代方案。這需要設定電子郵件。
-
在登入頁面,按 Sign in with email
-
輸入你的電子郵件地址
-
查看收件匣中的登入連結
-
按連結進行驗證(有效期 15 分鐘)
OAuth 登入
EmDash 在設定後支援 GitHub 和 Google 的 OAuth 登入。使用者可在初始通行密鑰設定後連結他們的帳號。
請參閱設定指南以了解設定方式。
使用者角色
EmDash 使用基於角色的存取控制,分為五個等級:
| 角色 | 等級 | 說明 |
|---|---|---|
| Subscriber | 10 | 僅限檢視 |
| Contributor | 20 | 建立內容(需審核) |
| Author | 30 | 建立/編輯/發佈自己的內容 |
| Editor | 40 | 管理所有內容 |
| Admin | 50 | 完整存取,包含設定 |
每個角色繼承所有較低等級的權限。第一位使用者一律建立為 Admin。
邀請使用者
管理員可透過管理後台邀請新使用者:
-
前往 Settings > Users
-
按 Invite User
-
輸入使用者的電子郵件並選擇角色
-
按 Send Invite
-
使用者會收到包含邀請連結的電子郵件
-
他們點選連結並註冊通行密鑰
邀請有效期為 7 天。管理員可從 Users 頁面重新傳送或撤銷邀請。
管理通行密鑰
使用者可在帳號設定中管理通行密鑰:
- 新增通行密鑰 — 為備份或其他裝置註冊額外的通行密鑰
- 移除通行密鑰 — 刪除不再使用的通行密鑰
- 重新命名通行密鑰 — 為通行密鑰設定描述性名稱
每位使用者最多可註冊 10 個通行密鑰。
自助註冊
對於團隊網站,你可以為特定電子郵件網域啟用自助註冊:
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
auth: {
selfSignup: {
domains: ["example.com"],
defaultRole: "contributor",
},
},
}),
],
});
符合電子郵件網域的使用者可以不需邀請即可註冊。他們會收到驗證電子郵件並註冊通行密鑰以完成註冊。
工作階段設定
工作階段使用安全的 HttpOnly cookie,並有合理的預設值:
emdash({
auth: {
session: {
maxAge: 30 * 24 * 60 * 60, // 30 天(預設)
sliding: true, // 活動時重設過期時間
},
},
});
安全注意事項
- 通行密鑰以公鑰儲存 — 私鑰永遠不會離開你的裝置
- 挑戰驗證防止重放攻擊
- 速率限制防止暴力破解(每分鐘每 IP 5 次嘗試)
- 工作階段為 HttpOnly、Secure、SameSite=Lax 以確保 cookie 安全
- 魔法連結權杖以 SHA-256 雜湊 — 原始權杖不會被儲存
疑難排解
「No passkeys registered」
如果在登入時看到此錯誤,你的通行密鑰可能已從密碼管理工具中刪除。請管理員傳送魔法連結或新的邀請。
「Passkey authentication failed」
這通常表示通行密鑰是為不同的網域建立的。通行密鑰綁定網域 — 為 localhost:4321 建立的通行密鑰無法在 example.com 上使用。為每個網域註冊新的通行密鑰。
「Session expired」
工作階段預設為 30 天,帶有滑動過期。如果意外被登出,請清除 cookie 並重新登入。
遺失所有通行密鑰
如果你已失去所有已註冊通行密鑰的存取權:
- 請另一位管理員傳送魔法連結(需要設定電子郵件)
- 使用魔法連結登入
- 在帳號設定中註冊新的通行密鑰
如果你是唯一的管理員且未設定電子郵件,你需要透過資料庫重設網站的驗證。
Cloudflare Access
部署到 Cloudflare 時,你可以使用 Cloudflare Access 作為驗證提供者來取代通行密鑰。Access 使用你現有的身分提供者在邊緣處理驗證。
為何使用 Cloudflare Access?
- 單一登入 — 使用者透過公司的 IdP 進行驗證
- 集中存取控制 — 在 Cloudflare 儀表板中管理誰可以存取管理後台
- 無需管理通行密鑰 — 不需要註冊或管理通行密鑰
- 群組角色對應 — 自動將 IdP 群組對應到 EmDash 角色
設定
- 為你的 EmDash 網站建立 Cloudflare Access 應用程式
- 從應用程式設定中記下 Application Audience (AUD) Tag
- 設定 EmDash 使用 Access:
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import emdash from "emdash/astro";
import { d1, access } from "@emdash-cms/cloudflare";
export default defineConfig({
output: "server",
adapter: cloudflare(),
integrations: [
emdash({
database: d1({ binding: "DB" }),
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audience: "abc123def456...", // 來自 Access 應用程式設定
}),
}),
],
});
設定選項
| 選項 | 類型 | 預設值 | 說明 |
|---|---|---|---|
teamDomain | string | 必填 | Access 團隊網域(例如 myteam.cloudflareaccess.com) |
audience | string | 必填 | Access 設定中的 Application Audience (AUD) 標籤 |
autoProvision | boolean | true | 首次 Access 登入時建立 EmDash 使用者 |
defaultRole | number | 30 | 未匹配任何群組的使用者角色(30 = Author) |
syncRoles | boolean | false | 每次登入時依 IdP 群組更新角色 |
roleMapping | object | — | 將 IdP 群組名稱對應到角色等級 |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | audience 標籤的環境變數名稱(替代寫死方式) |
角色對應
將你的 IdP 群組對應到 EmDash 角色:
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audience: "abc123...",
roleMapping: {
Admins: 50, // Admin
"Content Editors": 40, // Editor
Writers: 30, // Author
},
defaultRole: 20, // 未在任何群組中的使用者為 Contributor
}),
});
如果使用者屬於多個群組,則第一個匹配的群組獲勝。第一位存取網站的使用者無論群組為何,一律成為 Admin。
角色同步行為
預設(syncRoles: false)下,使用者的角色在首次登入時設定,之後不會變更。這允許管理員在 EmDash 中手動調整角色。
設定 syncRoles: true 以讓 IdP 群組成為權威來源 — 使用者的角色會在每次登入時根據其目前群組進行更新。
運作方式
- 使用者造訪
/_emdash/admin - Cloudflare Access 攔截並重新導向到你的 IdP
- 使用者進行驗證(SSO、MFA 等)
- Access 在請求中設定已簽署的 JWT
- EmDash 驗證 JWT 並建立/驗證使用者
停用的功能
啟用 Access 後,以下功能不可用:
- 登入頁面(
/_emdash/admin/login) - 通行密鑰註冊和管理
- OAuth 登入
- 魔法連結登入
- 自助註冊
- 使用者邀請
使用者管理完全透過你的 Cloudflare Access 政策完成。
疑難排解
「No Access JWT present」
請求在沒有 Access JWT 的情況下到達 EmDash。這表示:
- Access 未設定為保護你的應用程式
- Access 政策未匹配管理路由
驗證你的 Access 應用程式涵蓋 /_emdash/admin/*。
「JWT audience mismatch」
設定中的 audience 與 JWT 不匹配。請仔細核對 Access 應用程式設定中的 Application Audience Tag。
「User not authorized」
使用者透過 Access 驗證但 autoProvision 為 false 且他們不存在於 EmDash 中。你可以:
- 設定
autoProvision: true,或 - 在他們登入前手動建立使用者