驗證

本頁內容

EmDash 使用通行密鑰驗證作為主要登入方式。通行密鑰可防釣魚、不需要密碼,且可透過瀏覽器或密碼管理工具跨裝置使用。

對於 Cloudflare 部署,你可以選擇使用 Cloudflare Access 作為替代驗證提供者。

運作方式

通行密鑰使用 WebAuthn——一種建立公開金鑰憑證的網頁標準,憑證儲存在你的裝置上或透過密碼管理工具同步。登入時,你的裝置會證明持有該憑證,而不會透過網路傳送密碼。

通行密鑰驗證的優點:

  • 無需記憶或外洩的密碼
  • 防釣魚 — 憑證綁定到你網站的網域
  • 跨裝置同步 — 支援 iCloud 鑰匙圈、Google 密碼管理工具、1Password 等
  • 快速登入 — 一次觸控即可透過生物辨識或 PIN

首位使用者設定

第一次存取管理後台時,設定精靈會引導你建立管理員帳號。

  1. 前往 http://localhost:4321/_emdash/admin

  2. 你會被重新導向設定精靈。輸入:

    • Site Title — 網站名稱
    • Tagline — 簡短描述
    • Admin Email — 你的電子郵件
  3. Create Site 以註冊通行密鑰

  4. 瀏覽器會提示你建立通行密鑰:

    • macOS:Touch ID、裝置密碼或安全金鑰
    • Windows:Windows Hello 或安全金鑰
    • 行動裝置:Face ID、指紋或 PIN
  5. 通行密鑰註冊完成後,你就會登入並被導向管理儀表板。

登入

設定完成後,返回管理後台會觸發通行密鑰驗證:

  1. 造訪 /_emdash/admin

  2. 如果尚未登入,你會看到登入頁面

  3. Sign in 進行驗證

  4. 瀏覽器會提示你使用通行密鑰(生物辨識、PIN 或安全金鑰)

  5. 驗證後,你會被導向管理儀表板

魔法連結備援

如果無法使用通行密鑰(例如遺失裝置),魔法連結提供替代方案。這需要設定電子郵件。

  1. 在登入頁面,按 Sign in with email

  2. 輸入你的電子郵件地址

  3. 查看收件匣中的登入連結

  4. 按連結進行驗證(有效期 15 分鐘)

OAuth 登入

EmDash 在設定後支援 GitHub 和 Google 的 OAuth 登入。使用者可在初始通行密鑰設定後連結他們的帳號。

請參閱設定指南以了解設定方式。

使用者角色

EmDash 使用基於角色的存取控制,分為五個等級:

角色等級說明
Subscriber10僅限檢視
Contributor20建立內容(需審核)
Author30建立/編輯/發佈自己的內容
Editor40管理所有內容
Admin50完整存取,包含設定

每個角色繼承所有較低等級的權限。第一位使用者一律建立為 Admin。

邀請使用者

管理員可透過管理後台邀請新使用者:

  1. 前往 Settings > Users

  2. Invite User

  3. 輸入使用者的電子郵件並選擇角色

  4. Send Invite

  5. 使用者會收到包含邀請連結的電子郵件

  6. 他們點選連結並註冊通行密鑰

邀請有效期為 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 並重新登入。

遺失所有通行密鑰

如果你已失去所有已註冊通行密鑰的存取權:

  1. 請另一位管理員傳送魔法連結(需要設定電子郵件)
  2. 使用魔法連結登入
  3. 在帳號設定中註冊新的通行密鑰

如果你是唯一的管理員且未設定電子郵件,你需要透過資料庫重設網站的驗證。

Cloudflare Access

部署到 Cloudflare 時,你可以使用 Cloudflare Access 作為驗證提供者來取代通行密鑰。Access 使用你現有的身分提供者在邊緣處理驗證。

為何使用 Cloudflare Access?

  • 單一登入 — 使用者透過公司的 IdP 進行驗證
  • 集中存取控制 — 在 Cloudflare 儀表板中管理誰可以存取管理後台
  • 無需管理通行密鑰 — 不需要註冊或管理通行密鑰
  • 群組角色對應 — 自動將 IdP 群組對應到 EmDash 角色

設定

  1. 為你的 EmDash 網站建立 Cloudflare Access 應用程式
  2. 從應用程式設定中記下 Application Audience (AUD) Tag
  3. 設定 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 應用程式設定
			}),
		}),
	],
});

設定選項

選項類型預設值說明
teamDomainstring必填Access 團隊網域(例如 myteam.cloudflareaccess.com
audiencestring必填Access 設定中的 Application Audience (AUD) 標籤
autoProvisionbooleantrue首次 Access 登入時建立 EmDash 使用者
defaultRolenumber30未匹配任何群組的使用者角色(30 = Author)
syncRolesbooleanfalse每次登入時依 IdP 群組更新角色
roleMappingobject將 IdP 群組名稱對應到角色等級
audienceEnvVarstring"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 群組成為權威來源 — 使用者的角色會在每次登入時根據其目前群組進行更新。

運作方式

  1. 使用者造訪 /_emdash/admin
  2. Cloudflare Access 攔截並重新導向到你的 IdP
  3. 使用者進行驗證(SSO、MFA 等)
  4. Access 在請求中設定已簽署的 JWT
  5. 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 驗證但 autoProvisionfalse 且他們不存在於 EmDash 中。你可以:

  • 設定 autoProvision: true,或
  • 在他們登入前手動建立使用者