跳至主要內容
Skip to content

SSO、SAML 與 OIDC

前面幾篇談的是一般第三方登入:

text
使用 Google 登入
使用 LINE 登入
使用 GitHub 登入

但企業登入會再往前一步:

text
使用公司的身份系統登入

例如:

  • Okta。
  • Microsoft Entra ID。
  • Google Workspace。
  • OneLogin。
  • Auth0 / Azure AD B2C。
  • 公司自建 IdP。

這時候問題不只是「使用者是誰」,而是:

text
這個人屬於哪個公司?
這家公司是否允許他登入?
他在公司裡是什麼角色?
他離職後要不要自動失效?

這就是 SSO、SAML、OIDC 進入企業登入設計的地方。

一、 一句話回答

如果面試官問:

SSO、SAML、OIDC 是什麼?差在哪?

可以先回答:

SSO 是單一登入的產品能力,讓使用者登入一次企業身份系統後,可以存取多個服務;SAML 和 OIDC 則是實作 SSO 的常見協議。SAML 2.0 是較早也很常見的企業聯邦身份標準,使用 XML assertion,角色通常叫 IdP 和 SP;OIDC 是建立在 OAuth 2.0 之上的身份層,使用 ID Token、claims、UserInfo,角色通常叫 OP 和 RP。企業登入不只是驗證 token 或 assertion,還要處理 tenant、domain verification、issuer、audience、subject、group/role claims、JIT provisioning、SCIM deprovisioning、IdP initiated / SP initiated flow、session 與權限映射。

短一點可以說:

text
SSO 是能力;
SAML 和 OIDC 是協議;
企業登入的核心是信任關係、租戶歸屬與帳號生命週期。

二、 SSO 是什麼

SSO 是 Single Sign-On,單一登入。

它的目標是:

text
使用者登入一次身份提供者,
就能使用多個受信任的應用。

例如公司員工早上登入 Okta,接著可以進:

  • Slack。
  • GitHub Enterprise。
  • Notion。
  • Jira。
  • 內部後台。
  • HR 系統。

使用者不需要每個系統都各自設定密碼。

SSO 的好處:

  • 使用者少記多組密碼。
  • 公司可以集中管理登入政策。
  • 可統一要求 MFA。
  • 員工離職時可集中停用。
  • 安全事件可集中稽核。
  • 企業採購 SaaS 時更容易治理帳號。

但 SSO 不是魔法。應用系統仍要處理:

  • 哪個 tenant 可以用哪個 IdP。
  • 使用者第一次登入時要不要建帳號。
  • claims 如何映射角色。
  • IdP 停用使用者後本地帳號怎麼同步。
  • 本地 session 怎麼建立與撤銷。
  • 管理員誤設定時如何避免帳號接管。

三、 角色:IdP、SP、OP、RP

在企業登入裡,有幾個名詞一定要分清楚。

名稱常見於意義
IdPSAML / 泛稱Identity Provider,身份提供者
SPSAMLService Provider,服務提供者
OPOIDCOpenID Provider,OIDC 身份提供者
RPOIDCRelying Party,依賴 OP 身份聲明的應用
TenantSaaS 系統公司、組織、工作區或租戶

如果用 SAML 說:

text
Okta 是 IdP。
你的 SaaS 是 SP。

如果用 OIDC 說:

text
Okta / Microsoft Entra ID 是 OP。
你的 SaaS 是 RP。

如果用比較通俗的話說:

text
企業身份系統負責驗證使用者;
你的產品負責信任它的結果,並建立自己的本地登入狀態。

四、 SAML 與 OIDC 的差異

比較SAML 2.0OIDC
基礎格式XMLJSON / JWT
身份聲明AssertionID Token / claims
常見場景傳統企業 SSO、舊系統、SaaS 採購整合新系統、Web/mobile/API 友善、OAuth 生態
角色IdP / SPOP / RP
metadataXML metadatadiscovery document / JWKS
簽章XML SignatureJWT Signature
開發體驗較重,XML 驗證細節多較輕,現代 API 生態友善
流程Browser redirect / POST bindingAuthorization Code Flow / PKCE

面試時不要簡化成:

text
SAML 舊,OIDC 新,所以 OIDC 一定比較好。

比較準確的說法是:

text
SAML 仍然大量存在於企業 SSO;
OIDC 更適合現代 Web、mobile、API 與 OAuth 生態;
選哪個常取決於客戶 IdP、企業 IT 政策與產品整合成本。

很多 B2B SaaS 會兩個都支援。

五、 SP-Initiated 與 IdP-Initiated

SP-Initiated

SP-Initiated 是使用者先從你的產品開始登入:

text
使用者打開 app.example.com
-> 輸入公司 email 或選 tenant
-> 你的產品導向該公司的 IdP
-> IdP 登入成功後回到你的產品

流程比較像:

這是比較容易控制風險的方式,因為你的系統知道:

  • 使用者想進哪個 tenant。
  • 應該使用哪個 IdP。
  • callback 應該對應哪次登入 flow。
  • state / relay state 可以綁定流程。

IdP-Initiated

IdP-Initiated 是使用者從 IdP dashboard 點你的應用:

text
使用者登入 Okta
-> 點你的 SaaS app
-> Okta 直接送 assertion 到你的 ACS endpoint

它使用者體驗很好,但風險和複雜度更高:

  • 你的產品可能不知道使用者原本想進哪個 tenant。
  • request/response 綁定較弱。
  • relay state 處理要小心 open redirect。
  • 多 tenant 下要能靠 issuer / entity id 判斷來源。

很多企業客戶會要求 IdP-Initiated,但產品要清楚它和 SP-Initiated 的安全差異。

六、 SAML 登入流程

SAML 常見 SP-Initiated 流程:

幾個重要名詞:

名稱說明
Entity IDSP 或 IdP 的唯一識別
SSO URLIdP 接收登入請求的位置
ACS URLAssertion Consumer Service,SP 接收 SAMLResponse 的 endpoint
SAMLResponseIdP 回傳的 XML response
Assertion裡面包含身份聲明、subject、attributes、conditions
NameIDSAML 中常見的使用者識別
Metadata描述 IdP/SP endpoint、憑證、entity id 等設定

驗證 SAML Response 時要注意:

  • 簽章是否有效。
  • 簽章憑證是否來自該 tenant 設定的 IdP。
  • issuer 是否正確。
  • audience 是否是你的 SP entity ID。
  • recipient / destination 是否是你的 ACS URL。
  • assertion 是否過期。
  • NotBefore / NotOnOrAfter 是否合理。
  • InResponseTo 是否對應本次 AuthnRequest。
  • NameID 或 subject 是否穩定。
  • attribute mapping 是否符合預期。

不要只解析 XML 拿 email。

SAML 最大的坑之一就是 XML Signature 驗證做錯,或驗了 response 但沒有驗 assertion,或沒有處理 XML wrapping attack。實務上應使用成熟且維護良好的 SAML library,不要自己手寫 XML 簽章驗證。

七、 OIDC 企業登入流程

OIDC 的企業登入本質上和前面講的第三方登入相似,但多了 tenant 與企業政策。

典型流程:

OIDC 驗證重點:

  • issuer。
  • audience。
  • expiration。
  • nonce。
  • signature / JWKS。
  • subject。
  • authorized party,若適用。
  • email_verified,若使用 email。
  • tenant id / organization claim,若 Provider 有提供。

企業 OIDC 的資料模型通常不是:

text
provider = google

而是:

text
tenant_id = acme
issuer = https://login.microsoftonline.com/{tenant}/v2.0
subject = ...

同一個 email 在不同 tenant 下可能代表不同身份,不要只用 email 跨 tenant 合併。

八、 Tenant 與 Domain Verification

B2B SaaS 最重要的問題之一是:

text
如何知道這個 email 屬於哪個企業 tenant?

常見做法:

  1. 使用者輸入 email。
  2. 系統取 domain,例如 acme.com
  3. 查這個 domain 是否已被某個 tenant 驗證。
  4. 若該 tenant 啟用 SSO,導向它的 IdP。

但 domain routing 不能只靠字串。

企業要先完成 domain verification,例如:

  • DNS TXT record。
  • 上傳驗證檔。
  • 發送到管理員 email。
  • IdP metadata 驗證。

資料模型可以像:

sql
create table tenants (
  id uuid primary key,
  name text not null,
  slug text unique not null
);

create table tenant_domains (
  id uuid primary key,
  tenant_id uuid not null references tenants(id),
  domain text not null,
  verified boolean not null default false,
  verified_at timestamp,
  unique (domain)
);

create table sso_connections (
  id uuid primary key,
  tenant_id uuid not null references tenants(id),
  protocol text not null,
  issuer text not null,
  entity_id text,
  sso_url text,
  jwks_uri text,
  metadata_url text,
  enabled boolean not null default false,
  created_at timestamp not null
);

重點:

  • domain 必須唯一歸屬。
  • 未驗證 domain 不能用來自動導向企業 SSO。
  • SSO connection 要綁 tenant。
  • issuer/entity ID 要綁該 tenant 的設定。
  • callback 時要確認回來的 IdP 是該 tenant 預期的 IdP。

九、 JIT Provisioning

JIT 是 Just-In-Time provisioning。

意思是:

text
使用者第一次透過企業 SSO 登入時,系統自動建立本地帳號。

例如 IdP assertion / ID Token 告訴你:

text
subject = 00u123
email = alice@acme.com
name = Alice
groups = ["engineering"]

你的系統可以建立:

text
tenant = Acme
user = Alice
membership = engineering role
external identity = issuer + subject

JIT 要注意:

  • tenant 是否允許 JIT。
  • email domain 是否屬於 tenant。
  • subject 是否穩定。
  • groups 是否可信且已映射。
  • 預設角色不能過高。
  • 第一次登入是否需要管理員批准。
  • 如果同 email 已有本地帳號,是否要合併或要求驗證。

JIT 最常見錯誤是:

text
只要 SSO 回來就建立 admin。

比較安全的做法:

text
JIT 只建立最低權限 membership,
角色提升由管理員或明確 group mapping 控制。

十、 SCIM 與 Deprovisioning

JIT 解決的是「登入時建立帳號」。

但企業更在意的是:

text
員工離職後,帳號是否會被停用?

這就是 SCIM 常出現的地方。

SCIM 是跨系統管理使用者與群組生命週期的協議。企業 IdP 可以透過 SCIM 呼叫你的產品:

  • 建立使用者。
  • 更新使用者。
  • 停用使用者。
  • 同步群組。
  • 移除 membership。

沒有 SCIM 的系統常遇到:

text
員工已從公司離職,
但你的 SaaS 裡的 session 還活著。

所以企業登入的完整設計通常是:

能力解決問題
SSO使用企業身份登入
JIT第一次登入時建立本地 user
SCIM從 IdP 同步 user/group 生命週期
Session revocation停用後撤銷既有 session
Audit log追蹤誰登入、誰被停用、誰改權限

如果 user 被 SCIM deprovision:

  • 停用 membership。
  • 撤銷 refresh token。
  • 撤銷 active sessions。
  • 阻止後續 SSO 登入。
  • 保留 audit log。
  • 不一定刪除歷史資料,避免資料歸屬消失。

十一、 Groups 與 Role Mapping

企業 IdP 常會傳 group claims:

json
{
  "groups": ["engineering", "admin"]
}

但不要無腦把 group 字串當本地權限。

你應該有 mapping:

text
IdP group "acme-engineering" -> product role "developer"
IdP group "acme-admins" -> product role "admin"

原因:

  • 不同企業 group 命名不同。
  • group 名稱可能被改。
  • 有些 Provider 傳 group id,有些傳 group name。
  • group claim 可能太大而需要另外查 API。
  • admin 權限應該可被產品管理員確認。

比較好的模型:

sql
create table sso_group_mappings (
  id uuid primary key,
  tenant_id uuid not null references tenants(id),
  sso_connection_id uuid not null references sso_connections(id),
  external_group text not null,
  product_role text not null,
  unique (tenant_id, sso_connection_id, external_group)
);

登入時:

text
驗證 assertion/token -> 取得 groups -> 套用 mapping -> 更新 membership roles

高權限 role 建議:

  • 要有明確 mapping。
  • 預設不自動給 admin。
  • 變更 mapping 要記 audit log。
  • 對 admin role 可要求額外確認。

十二、 SSO 與本地 Session

SSO 成功後,你的產品仍然要建立自己的 session。

不要每次 API request 都去問 IdP:

text
這個使用者現在還登入嗎?

常見做法:

text
SSO 驗證成功 -> 建立本地 session -> 後續 API 使用本地 session

但要注意企業停用同步:

  • 若 SCIM 停用 user,要撤銷 session。
  • 若 tenant 關閉 SSO,要重新評估登入方式。
  • 若 user role 改變,session 中的權限要能更新。
  • 若 IdP 發出 logout 事件,視協議支援處理 SLO。

SAML 有 Single Logout 機制,但實務整合常比想像複雜,不一定每個 IdP / SP 都可靠支援。很多產品會以本地 session 管理、SCIM deprovision、短效 session 和風險控制為主。

十三、 Multi-tenant 風險

企業登入最危險的錯誤之一是 tenant mix-up。

例如:

text
使用者從 tenant A 的 IdP 登入,
結果被放進 tenant B。

防線:

  • SSO connection 必須綁 tenant。
  • issuer/entity ID 必須符合 tenant 設定。
  • domain routing 只使用 verified domain。
  • callback state 綁定 tenant id。
  • subject 只在 issuer 下有效。
  • email 不可跨 tenant 自動合併。
  • group mapping 必須 tenant-scoped。

資料庫唯一鍵也要考慮 tenant:

text
unique (tenant_id, issuer, subject)

或:

text
unique (sso_connection_id, subject)

避免不同企業 IdP 的 subject 撞在一起。

十四、 常見錯誤

1. 只用 email 決定 tenant

錯誤:

text
看到 alice@acme.com,就放進 Acme tenant。

正確:

text
domain 必須被 tenant 驗證,SSO callback 也要驗 issuer/entity ID。

2. SAML 只 parse 不驗簽

錯誤:

text
解析 SAMLResponse XML,拿 NameID 和 email 建 session。

正確:

text
驗簽章、issuer、audience、recipient、destination、conditions、InResponseTo。

3. OIDC 只 decode ID Token

錯誤:

text
jwtDecode(id_token)

正確:

text
驗 JWKS 簽章、issuer、audience、exp、nonce、subject。

4. JIT 預設給高權限

錯誤:

text
第一次 SSO 登入就給 admin。

正確:

text
預設最低權限,高權限由 group mapping 或管理員確認。

5. 沒有 deprovision

錯誤:

text
SSO 能登入就好,離職不管。

正確:

text
支援 SCIM 或停用同步,並撤銷本地 session。

6. 忽略 IdP-Initiated 風險

錯誤:

text
任何 SAMLResponse POST 到 ACS 都接受。

正確:

text
根據 issuer/entity ID 找 tenant,驗簽與 audience,限制 relay state,並防 tenant mix-up。

十五、 面試追問題庫

Q1:SSO、SAML、OIDC 的關係是什麼?

SSO 是單一登入能力,SAML 和 OIDC 是常見實作協議。SAML 使用 XML assertion,常見角色是 IdP / SP;OIDC 建立在 OAuth 2.0 上,使用 ID Token 和 claims,常見角色是 OP / RP。

Q2:SAML 和 OIDC 怎麼選?

如果客戶是傳統企業、既有 IdP 或舊 SaaS 生態,SAML 仍很常見。如果是新系統、mobile、API 或 OAuth 生態,OIDC 通常更友善。B2B SaaS 常會兩者都支援,因為真正決定的是客戶 IdP 能力與企業 IT 政策。

Q3:企業 SSO 為什麼不能只看 email?

因為 email 是屬性,不是聯邦身份主鍵。同一 email 可能出現在不同 tenant,email 也可能變更。企業 SSO 應使用 tenant + issuer/entity ID + subject/NameID 建立身份映射。

Q4:什麼是 JIT provisioning?

JIT 是使用者第一次透過 SSO 登入時,系統根據 IdP assertion/token 自動建立本地 user 或 tenant membership。它要搭配最低權限、domain/tenant 驗證與 group mapping,避免第一次登入就取得過高權限。

Q5:SCIM 解決什麼問題?

SCIM 解決使用者與群組的生命週期同步,例如建立、更新、停用、群組同步。它特別重要的是 deprovisioning:員工離職或被移出群組後,你的產品要停用帳號、撤銷 session 或更新權限。

Q6:IdP-Initiated SSO 有什麼風險?

IdP-Initiated 是使用者從 IdP dashboard 點 app,IdP 直接送 assertion 給 SP。它體驗好,但 request/response 綁定較弱,多 tenant 下要更小心 issuer/entity ID、relay state、audience、tenant routing 與 open redirect。

Q7:SSO 成功後,還需要本地 session 嗎?

需要。SSO 只證明外部身份驗證成功;你的產品仍要建立自己的 session,並負責權限、撤銷、session 有效期、裝置管理、audit log 與本地安全策略。

十六、 實作題

題目一:設計企業 SSO connection 資料表

請支援:

  • 一個 tenant 多個 SSO connection。
  • 支援 SAML 與 OIDC。
  • domain verification。
  • issuer/entity ID 驗證。
  • 啟用 / 停用。

可以從這些表開始:

text
tenants
tenant_domains
sso_connections
sso_group_mappings
tenant_memberships

題目二:設計 SP-Initiated SAML 登入

請描述:

  1. 使用者輸入 email 或 tenant slug。
  2. 找到 verified domain / tenant。
  3. 找到 tenant 的 SAML connection。
  4. 產生 AuthnRequest 與 RelayState。
  5. Redirect 到 IdP。
  6. ACS 收到 SAMLResponse。
  7. 驗簽章、issuer、audience、destination、conditions、InResponseTo。
  8. 使用 issuer + NameID/subject 找 external identity。
  9. JIT 建立 user/membership。
  10. 建立本地 session。

題目三:設計 deprovision 流程

情境:

text
企業 IdP 通知使用者 alice@acme.com 已停用。

請設計你的產品要做什麼。

好的答案應包含:

  • 停用 tenant membership。
  • 撤銷 refresh token。
  • 撤銷 active sessions。
  • 保留 audit log。
  • 不刪歷史資料。
  • 阻止後續 SSO 登入。
  • 必要時通知 tenant admin。

十七、 資深視角

1. SSO 是信任關係,不只是登入按鈕

企業 SSO 的本質是:

text
你的產品信任某個企業 IdP 對某個 tenant 的身份聲明。

所以你要驗的是:

  • 是不是這個 IdP。
  • 是不是這個 tenant。
  • assertion/token 是不是給你的產品。
  • 使用者 subject 是否穩定。
  • claims 是否符合政策。

2. 租戶邊界比登入成功更重要

登入成功只代表使用者通過 IdP。

但 B2B SaaS 還要問:

text
他能不能進這個 workspace?
他是不是這個 tenant 的成員?
他是不是 admin?
他是否已被停用?

tenant boundary 錯,比登入失敗更嚴重。

3. 身份、成員資格、權限要分開

好的模型通常會拆成:

text
User:全域使用者
ExternalIdentity:外部身份
TenantMembership:使用者在某 tenant 的成員資格
Role/Permission:在 tenant 內能做什麼
Session:這次登入狀態

不要把 SSO subject 直接等同於全域 user,也不要把 email 直接等同於 tenant membership。

4. 企業登入的完整性在生命週期

能登入只是開始。

真正成熟的企業身份整合要處理:

  • onboarding。
  • JIT。
  • group mapping。
  • role sync。
  • deprovisioning。
  • session revocation。
  • audit log。
  • admin recovery。
  • IdP metadata rotation。
  • certificate rotation。

這些才是資深工程師在系統設計題裡應該補上的部分。


總結

問題回答重點
SSO單一登入能力
SAMLXML assertion,企業 SSO 常見
OIDCOAuth 2.0 上的身份層,ID Token / claims
IdP / SPSAML 的身份提供者與服務提供者
OP / RPOIDC 的身份提供者與依賴方
Tenant企業、組織、工作區邊界
JIT第一次 SSO 登入時建立 user/membership
SCIM同步 user/group 生命週期與停用
最大風險tenant mix-up、只信 email、不驗簽、不處理 deprovision

一句完整的面試回答可以是:

SSO 是單一登入能力,SAML 和 OIDC 是常見的企業 SSO 協議。SAML 2.0 使用 XML assertion,角色是 IdP 和 SP;OIDC 建立在 OAuth 2.0 上,使用 ID Token、claims、UserInfo,角色是 OP 和 RP。企業登入不只是驗證使用者身份,還要確認 tenant 邊界與信任關係,例如 issuer/entity ID、audience、subject/NameID、domain verification、group mapping 與本地 membership。實作時應使用成熟 library 驗證 SAML 簽章或 OIDC ID Token,不能只 parse email;SSO 成功後仍要建立本地 session,並處理 JIT provisioning、SCIM deprovisioning、session 撤銷、audit log 與角色映射。資深設計會把 User、ExternalIdentity、TenantMembership、Role、Session 分開,避免 tenant mix-up 和 account takeover。

延伸閱讀