Search K
OIDC / 單一登入
SnapOtter 支援 OpenID Connect(OIDC)進行單一登入。使用者可以透過外部身分供應商(例如 Keycloak、Authentik、Google 或 Microsoft Entra ID)登入,取代本機使用者名稱/密碼驗證(或與之並用)。
快速開始
將這些環境變數加入你的 docker-compose.yml:
yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
environment:
EXTERNAL_URL: "https://photos.example.com"
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"你的供應商所使用的重新導向 URI 一律為:
${EXTERNAL_URL}/api/auth/oidc/callback舉例來說,如果 EXTERNAL_URL 是 https://photos.example.com,請將供應商的重新導向 URI 設定為 https://photos.example.com/api/auth/oidc/callback。
設定參考
| 變數 | 預設值 | 說明 |
|---|---|---|
OIDC_ENABLED | false | 啟用 OIDC 登入。登入頁面會出現「使用 SSO 登入」按鈕。 |
OIDC_ISSUER_URL | 供應商的簽發者(issuer)URL。必須支援 OIDC Discovery(/.well-known/openid-configuration)。 | |
OIDC_CLIENT_ID | 向你的供應商註冊的 OAuth 用戶端 ID。 | |
OIDC_CLIENT_SECRET | OAuth 用戶端密鑰。 | |
OIDC_SCOPES | openid profile email | 以空格分隔的要求範圍(scope)清單。 |
OIDC_AUTO_CREATE_USERS | true | 在首次 OIDC 登入時自動建立本機使用者帳號。 |
OIDC_DEFAULT_ROLE | user | 指派給自動建立的 OIDC 使用者的角色。可為 admin、editor 或 user 其中之一。 |
OIDC_AUTO_LINK_USERS | false | 若電子郵件地址相符,將 OIDC 身分連結到現有的本機使用者。 |
OIDC_PROVIDER_NAME | 顯示在登入按鈕上的顯示名稱(例如「Keycloak」、「Google」)。若留空,按鈕會顯示「SSO」。 | |
OIDC_CLOCK_TOLERANCE | 30 | 用於權杖驗證的時鐘偏差容忍度(秒)。 |
OIDC_USERNAME_CLAIM | preferred_username | 用作新帳號使用者名稱的 ID 權杖宣告(claim)。 |
EXTERNAL_URL | SnapOtter 可被存取的公開 URL。OIDC 需要此值以建立正確的重新導向 URI。 | |
COOKIE_SECRET | 自動產生 | 用於簽署工作階段 cookie 的密鑰。執行多個複本時請明確設定此值。 |
供應商指南
Keycloak
- 建立新的 realm(或使用現有的)。
- 前往 Clients 並建立新的用戶端:
- Client ID:
snapotter - Client authentication:開啟(confidential)
- Authentication flow:Standard flow(Authorization Code)
- Client ID:
- 在該用戶端的 Settings 分頁下,將 Valid redirect URIs 設為你的回呼 URL(例如
https://photos.example.com/api/auth/oidc/callback)。 - 從 Credentials 分頁複製 Client secret。
- 將
OIDC_ISSUER_URL設為https://keycloak.example.com/realms/your-realm。
Authentik
- 在管理介面中,前往 Applications > Providers 並建立新的 OAuth2/OpenID Provider。
- Client type:Confidential
- Redirect URIs:你的回呼 URL
- Signing key:選擇現有金鑰或建立一個
- 建立一個 Application 並將其連結到該供應商。
- 從供應商設定中複製 Client ID 與 Client Secret。
- 將
OIDC_ISSUER_URL設為https://authentik.example.com/application/o/snapotter/(結尾的斜線很重要)。
Google
- 前往 Google Cloud Console。
- 建立專案(或選擇現有的)。
- 導覽至 APIs & Services > OAuth consent screen 並進行設定。
- 前往 APIs & Services > Credentials 並建立 OAuth 2.0 Client ID:
- Application type:Web application
- Authorized redirect URIs:你的回呼 URL
- 複製 Client ID 與 Client secret。
- 將
OIDC_ISSUER_URL設為https://accounts.google.com。 - 將
OIDC_USERNAME_CLAIM設為email(Google 不提供preferred_username)。
Azure AD / Entra ID
- 在 Azure 入口網站中,前往 Microsoft Entra ID > App registrations > New registration。
- 將應用程式命名為「SnapOtter」。在 Redirect URI 下,選擇 Web 平台並輸入你的回呼 URL(例如
https://photos.example.com/api/auth/oidc/callback)。請勿選擇 Single-page application:SnapOtter 以用戶端密鑰進行驗證,而 Entra ID 在 SPA 註冊上會拒絕這種方式。 - 從 Overview 頁面複製 Application (client) ID 與 Directory (tenant) ID。
- 前往 Certificates & secrets > New client secret,並立即複製密鑰的 Value。它只會顯示一次,而旁邊的 Secret ID 並不是密鑰。
- 將
OIDC_ISSUER_URL設為https://login.microsoftonline.com/<tenant-id>/v2.0,使用步驟 3 中的 Directory (tenant) ID。 - 將
OIDC_USERNAME_CLAIM保留為預設值。Entra ID 會提供preferred_username,因此這裡不需要 Google 指南中的email覆寫。
簽發者 URL 中請一律使用你的租用戶 ID,而不是 common 或 organizations。這些多租用戶端點會把字面上的範本 {tenantid} 公告為其簽發者,因而無法通過 OIDC Discovery 驗證。
WARNING
Entra ID 的 preferred_username 對應使用者主體名稱(user principal name),當使用者被重新命名或移轉到其他租用戶時,這個名稱會跟著改變。SnapOtter 只會在首次登入時讀取一次此宣告,因此帳號之後仍會保留原本的使用者名稱。無論哪種情況,登入都能持續運作:回訪的使用者是以權杖中穩定的 subject 比對,而不是使用者名稱。
切換到 Entra ID 並不會關閉密碼登入。請參閱 停用本機登入。
Okta 與其他供應商
任何支援 OIDC Discovery 的供應商運作方式都相同:建立一個機密(confidential)Web 用戶端並填入你的回呼 URL,然後將 OIDC_ISSUER_URL 指向其簽發者。對於 Okta,請建立一個使用 OIDC - OpenID Connect 登入方法與 Web Application 類型的應用程式,然後使用你的 Okta 網域作為簽發者(例如 https://your-company.okta.com)。
SnapOtter 不會將身分供應商的群組對應到角色。新的 SSO 使用者會取得 OIDC_DEFAULT_ROLE,管理員可在 Settings > Users 下變更角色,而透過 OIDC_SCOPES 要求群組宣告不會有任何效果。
使用者佈建
自動建立
當 OIDC_AUTO_CREATE_USERS 為 true(預設)時,會在有人首次透過 OIDC 登入時建立本機使用者帳號。使用者名稱取自由 OIDC_USERNAME_CLAIM 指定的宣告,角色則設為 OIDC_DEFAULT_ROLE。
若發生使用者名稱衝突,會附加一個數字後綴(例如 jane 會變成 jane_2)。
自動連結
當 OIDC_AUTO_LINK_USERS 為 true 時,若電子郵件地址相符,SnapOtter 會將 OIDC 身分連結到現有的本機帳號。當你已預先建立使用者帳號,並希望他們在不遺失資料的情況下開始使用 SSO 時,這很有用。
WARNING
只有在你信任你的 OIDC 供應商會驗證電子郵件地址時,才啟用自動連結。未經驗證的電子郵件可能讓某人接管其他使用者的帳號。
停用本機登入
OIDC 不會停用本機使用者名稱/密碼登入。兩種方法都仍可使用。若 OIDC 供應商無法連線,管理員仍可使用本機憑證登入。
自簽憑證
如果你的 OIDC 供應商使用自簽或私有 CA 憑證,請將 CA 套件掛載進容器,並讓 NODE_EXTRA_CA_CERTS 指向它:
yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
volumes:
- ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
environment:
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"DANGER
請勿設定 NODE_TLS_REJECT_UNAUTHORIZED=0。這會停用所有 TLS 驗證,是一項安全風險。
使用明文 http 的簽發者
只有在 EXTERNAL_URL 也是明文 http 時,SnapOtter 才會接受 http:// 開頭的簽發者 URL,這適用於本機或區域網路的測試環境。此時探索請求、登入代碼交換和權杖都會以未加密的方式在網路上傳輸,因此 SnapOtter 會在啟動時記錄一則警告,並標明簽發者的主機。如果 EXTERNAL_URL 是 https://,使用 http 的簽發者會在登入時遭到拒絕,啟動警告也會說明這一點。無論哪種情況,解決方法都是透過 https 提供身分提供者服務。
疑難排解
重新導向 URI 不相符
最常見的錯誤。請檢查你的供應商所預期的內容與 SnapOtter 所送出的內容之間是否有以下差異:
http對https,配置方式必須完全相符- 結尾斜線,某些供應商對此很嚴格
- 連接埠號碼,若非標準連接埠請一併納入
- 路徑,必須是
/api/auth/oidc/callback
請再次確認 EXTERNAL_URL。它必須與使用者在瀏覽器中輸入的 URL 相符。
UNABLE_TO_VERIFY_LEAF_SIGNATURE
OIDC 供應商所使用的憑證不受 Node.js 信任。請參閱上方的 自簽憑證。
時鐘偏差錯誤
如果你的伺服器時鐘與 OIDC 供應商時鐘不同步,權杖驗證可能會失敗。請提高 OIDC_CLOCK_TOLERANCE(預設為 30 秒)。更好的做法是在兩台機器上都執行 NTP。
「OIDC provider unreachable」
SnapOtter 會在啟動時以及登入期間擷取供應商的探索文件。請檢查:
- 從 Docker 容器內部進行的 DNS 解析(
docker exec snapotter nslookup auth.example.com) - 容器與供應商之間的防火牆規則
OIDC_ISSUER_URL值,它必須能從伺服器連線,而不僅僅是從你的瀏覽器
缺少宣告
如果登入後使用者名稱或電子郵件為空,你的供應商可能沒有回傳預期的宣告。請驗證:
- 在
OIDC_SCOPES中設定的範圍包含profile與email - 供應商已設定為在 ID 權杖中包含由
OIDC_USERNAME_CLAIM指定的宣告 - 某些供應商需要明確的對應(mapper)/範圍設定才能釋出宣告
