身份驗證、授權與身份識別的差異
很多登入系統的混亂,都是從概念混在一起開始的:信箱驗證到底算不算登入?Google 登入是 OAuth 還是身份驗證?JWT 裡有 user id 是不是就代表有權限?401 和 403 到底差在哪?
一句話回答:身份識別 Identity Proofing 是確認「你是不是你宣稱的那個人」,身份驗證 Authentication 是確認「這次操作是不是本人登入」,授權 Authorization 是確認「登入後你能不能做這件事」;三者會串在同一個登入流程裡,但解決的是不同問題,系統設計時必須拆開。
一、 必考觀念
1. 三個概念解決三個問題
| 概念 | 英文 | 核心問題 | 常見例子 |
|---|---|---|---|
| 身份識別 | Identity Proofing | 你是不是你宣稱的那個人 | 信箱驗證、手機驗證、健保卡、自然人憑證 |
| 身份驗證 | Authentication | 這次登入是不是本人操作 | 帳號密碼、Session、TOTP、Passkey |
| 授權 | Authorization | 登入後你能做什麼 | RBAC、權限碼、API scope、資料權限 |
可以用一個句子記:
Identity Proofing:你是誰?
Authentication:你怎麼證明這次是你?
Authorization:你被允許做什麼?這三件事在產品上常常連在一起,但工程上最好拆開,否則會把安全責任放錯地方。
2. 註冊、登入、權限是不同階段
以一個普通會員系統為例:
註冊
-> 驗證信箱
-> 登入
-> 取得 session / token
-> 進入會員中心
-> 檢查是否能查看訂單、修改資料、刪除帳號每一步的安全意義不同:
| 流程 | 對應概念 | 說明 |
|---|---|---|
| 驗證信箱 | 身份識別的一部分 | 確認這個 email 可被使用者控制 |
| 輸入帳密 | 身份驗證 | 確認這次登入者知道正確憑證 |
| 建立 session | 身份驗證狀態 | 後續請求不用每次輸入密碼 |
| 檢查能否刪除訂單 | 授權 | 確認使用者是否有該操作權限 |
信箱驗證不是登入;登入成功也不代表什麼都能做。
3. 身份系統要分清楚「證明強度」
不同方式的可信程度不同:
| 方式 | 證明了什麼 | 強度 |
|---|---|---|
| 信箱驗證 | 使用者控制某個 email inbox | 低到中 |
| 手機 OTP | 使用者控制某個手機號碼 | 中 |
| 帳號密碼 | 使用者知道某組秘密 | 低到中,取決於密碼與防護 |
| TOTP | 使用者持有設定過的驗證器 | 中到高 |
| Passkey / WebAuthn | 使用者持有私鑰與裝置驗證器 | 高 |
| 自然人憑證 | 使用者持有憑證並知道 PIN | 高 |
| 健保卡 | 使用者持有特定身份載具 | 高,依整合流程而定 |
系統設計時要問:
這個場景需要多高的身份信任?
失敗或冒用的代價是什麼?
使用者體驗能承受多少驗證摩擦?不是所有產品都需要最高強度;但高風險場景不能只靠低強度驗證。
二、 Identity Proofing:身份識別
1. 身份識別是在建立信任
身份識別要回答:
這個帳號背後的人,是否真的控制某個身份憑證或聯絡方式?
常見例子:
- 使用者點擊信箱驗證連結。
- 使用者輸入手機簡訊 OTP。
- 使用者插入自然人憑證並輸入 PIN。
- 使用者用健保卡完成身份確認。
- 使用者在銀行臨櫃完成 KYC。
這些流程不一定等於「登入」。它們是在提高系統對使用者身份的信任程度。
2. 信箱驗證不是完整身份驗證
信箱驗證通常只能說明:
這個使用者目前能控制這個 email。它不能保證:
- 使用者真實姓名。
- 使用者年齡。
- 使用者是否為某個自然人。
- 使用者未來永遠控制這個信箱。
所以信箱驗證適合:
- 確認通知管道。
- 降低假帳號。
- 啟用帳號。
- 忘記密碼。
但不適合單獨用來證明高信任身份。
3. 身份識別可能需要分級
很多系統會有身份等級:
| 等級 | 例子 | 可以做什麼 |
|---|---|---|
| 未驗證 | 只註冊帳密 | 瀏覽、收藏 |
| 已驗證信箱 | 點擊 email link | 發文、接收通知 |
| 已驗證手機 | 完成 SMS OTP | 提高帳號恢復能力 |
| 已完成實名 | 憑證、文件、KYC | 金融、醫療、政府服務 |
這就是為什麼「帳號存在」和「身份可信」不能畫上等號。
三、 Authentication:身份驗證
1. Authentication 是登入本人
身份驗證要回答:
這次請求是不是由該帳號本人發起?
常見方式:
- 密碼。
- 一次性驗證碼。
- TOTP。
- Passkey。
- 憑證。
- 已存在的 session。
- 有效的 access token。
登入成功後,系統通常會建立某種登入狀態:
session id
access token
refresh token
device session後續請求會帶上這些憑證,讓伺服器知道「目前請求來自已驗證的登入狀態」。
延伸讀:HTTP 專題:Session 與 Token 的抉擇。
2. 認證因素分三類
常見 MFA 會把身份驗證因素分成三種:
| 因素 | 意義 | 例子 |
|---|---|---|
| 你知道的東西 | Knowledge | 密碼、PIN |
| 你擁有的東西 | Possession | 手機、驗證器、硬體金鑰、憑證卡 |
| 你本身的特徵 | Inherence | 指紋、Face ID、虹膜 |
多因素驗證的重點是不同因素組合,而不是「輸入兩次密碼」。
例如:
密碼 + TOTP
密碼 + Passkey
自然人憑證 + PIN這比單純帳號密碼更難被盜用。
3. 登入狀態不是使用者本人
這句很重要:
伺服器看到 session / token,只能知道這個請求帶著有效登入憑證,不等於百分之百知道本人坐在電腦前。
所以高風險操作常需要重新驗證:
- 修改密碼。
- 修改信箱。
- 提款、轉帳。
- 查看敏感個資。
- 下載醫療資料。
- 關閉 MFA。
這叫 step-up authentication,也就是在風險提高時要求更強的驗證。
四、 Authorization:授權
1. Authorization 是能不能做
授權要回答:
這個已登入使用者,是否被允許執行這個操作?
常見授權模型:
- Role-based access control:角色權限。
- Permission-based access control:權限碼。
- Attribute-based access control:根據屬性判斷。
- Scope-based access control:OAuth API scope。
- Data-level permission:資料範圍權限。
例如:
user:list
user:create
user:delete
order:refund
medical-record:read登入成功只代表 authentication 通過;是否能刪除使用者,要看 authorization。
延伸讀:Vue 專題:Vue 權限與路由守衛設計。
2. 401 和 403 差異
這是面試常問。
| 狀態碼 | 意義 | 例子 |
|---|---|---|
| 401 Unauthorized | 尚未通過身份驗證,或登入狀態失效 | 沒 token、session 過期 |
| 403 Forbidden | 已登入,但沒有權限 | 不是 admin、缺少 permission |
簡化記法:
401:你是誰,我還不知道或不再相信。
403:我知道你是誰,但你不能做這件事。前端處理也不同:
- 401:清登入狀態,導 login,保留 redirect。
- 403:顯示無權限頁面或禁用操作,不一定登出。
3. 前端授權不是安全邊界
前端可以做:
- 隱藏 menu。
- 禁用 button。
- 路由守衛。
- 顯示 403 頁。
- 根據權限調整 UI。
但真正授權必須在後端檢查:
每個敏感 API
每個資料範圍
每個高風險操作因為使用者可以繞過前端,直接呼叫 API。
五、 OAuth、OIDC 與第三方登入的常見混淆
1. OAuth 2.0 主要是授權框架
OAuth 2.0 的核心問題不是「登入你是誰」,而是:
使用者如何授權某個應用存取另一個服務上的資源?
例如:
你授權某個工具讀取你的 Google Calendar。這比較像授權,而不是純身份驗證。
2. OpenID Connect 才補上身份層
OpenID Connect 是建立在 OAuth 2.0 上的身份層,常用於第三方登入。
它會引入:
- id token。
- user claims。
- userinfo endpoint。
- subject identifier。
所以比較精準的說法是:
OAuth 2.0:授權存取資源。
OpenID Connect:在 OAuth 2.0 之上提供登入身份資訊。3. 第三方登入後仍要建立本地帳號
很多產品會讓使用者用 Google / LINE / GitHub 登入。
但系統內部通常仍要有自己的 user:
type User = {
id: string
email: string
status: 'active' | 'disabled'
}
type ExternalIdentity = {
provider: 'google' | 'line' | 'github'
providerUserId: string
userId: string
}原因是:
- 你的系統需要自己的權限模型。
- 使用者可能綁定多種登入方式。
- 第三方 email 可能變更或未驗證。
- 第三方帳號停用不一定等於本地帳號刪除。
第三方登入只解決「如何證明外部身份」,不等於你的系統授權已經完成。
六、 常見流程拆解
1. 一般會員註冊
使用者輸入 email/password
-> server 建立 pending user
-> 寄出 verification email
-> 使用者點擊連結
-> user.emailVerified = true
-> 使用者登入
-> 建立 session概念拆解:
| 步驟 | 概念 |
|---|---|
| 建立帳號 | 帳號資料建立 |
| 點擊驗證信 | 身份識別的一部分 |
| 輸入密碼登入 | 身份驗證 |
| 進入會員中心 | 需要授權檢查 |
2. 管理員登入後刪除使用者
admin 輸入帳密
-> 通過 MFA
-> 建立 admin session
-> 進入使用者管理頁
-> 點擊刪除
-> server 檢查 user:delete permission
-> 寫入 audit log概念拆解:
| 步驟 | 概念 |
|---|---|
| 帳密 + MFA | 身份驗證 |
| 進入管理頁 | 授權 |
| 刪除使用者 | 授權 + 稽核 |
| 高風險操作再次驗證 | Step-up authentication |
3. 政府或醫療服務登入
使用者選擇高信任登入方式
-> 使用健保卡、自然人憑證或行動身份工具
-> 系統確認身份
-> 建立服務內 session
-> 使用者查看或申辦服務
-> 高風險操作寫入稽核紀錄這類場景的重點是:
- 身份識別強度高。
- 操作紀錄重要。
- 可能需要重新驗證。
- 權限和資料範圍要非常嚴格。
政府憑證與醫療身份整合細節會變,正式寫到健保卡、自然人憑證、TW FidO 時應以官方文件為準。
七、 追問題庫
Q1:Authentication 和 Authorization 差在哪?
Authentication 是確認你是誰,或這次登入是否可信;Authorization 是確認你能不能做某件事。
例如登入成功是 authentication,登入後能不能刪除使用者是 authorization。
Q2:信箱驗證算不算身份驗證?
信箱驗證更接近身份識別或聯絡方式驗證。它證明使用者能控制某個 email,但不等於每次登入都由本人操作,也不等於能做所有敏感操作。
Q3:401 和 403 怎麼分?
401 是未登入、token 過期或身份驗證失敗;403 是已登入但權限不足。
401 通常導 login,403 通常顯示無權限。
Q4:OAuth 是身份驗證嗎?
OAuth 2.0 本身主要是授權框架。第三方登入常用的是 OpenID Connect,它在 OAuth 2.0 之上提供身份層,例如 id token 和 user claims。
面試時不要把 OAuth 和 OIDC 完全混在一起。
Q5:有 JWT 就代表有權限嗎?
不一定。
JWT 可能只是登入狀態或身份聲明。真正能不能操作某個 API,仍要看 token 內容、scope、permission,以及後端授權檢查。
Q6:前端路由守衛可以保護系統安全嗎?
只能改善體驗,不能當安全邊界。
前端路由守衛可以避免使用者看到不該看的頁面入口,但 API 權限和資料權限一定要後端檢查。
八、 實作題
題目:設計一個會員系統的身份流程
需求:
- 使用者可以註冊帳號。
- 註冊後要驗證信箱。
- 使用者可以登入。
- 登入後才能查看個人資料。
- 修改密碼前要重新驗證。
- 管理員可以停用使用者。
可以這樣拆:
Identity Proofing
-> email verification
Authentication
-> password login
-> session / token
-> re-auth before password change
Authorization
-> user can read own profile
-> admin can disable users
Audit
-> login success / failure
-> password change
-> admin disable user資料模型可以先簡化:
type User = {
id: string
email: string
emailVerified: boolean
passwordHash: string
status: 'pending' | 'active' | 'disabled'
}
type Session = {
id: string
userId: string
createdAt: string
expiresAt: string
lastAuthenticatedAt: string
}
type Permission = 'profile:read:self' | 'user:disable'API 判斷:
GET /me
-> 需要 authentication
-> 只能讀自己的資料
PATCH /me/password
-> 需要 authentication
-> 需要近期重新驗證
POST /admin/users/:id/disable
-> 需要 authentication
-> 需要 user:disable authorization
-> 寫 audit log這題的重點不是資料表多完整,而是能否把身份識別、身份驗證、授權、稽核拆清楚。
九、 資深視角
1. 身份信任是分層累積的
不要把所有使用者都看成同一種狀態。
例如:
未登入
已登入
已驗證 email
已啟用 MFA
已完成實名
近期完成重新驗證不同功能可以要求不同信任等級:
| 功能 | 要求 |
|---|---|
| 看公開內容 | 不需登入 |
| 留言 | 已登入或已驗證 email |
| 修改密碼 | 已登入 + 近期重新驗證 |
| 提款 | 已登入 + MFA + 風險檢查 |
| 查看醫療資料 | 高信任身份 + 稽核 |
這比單純 isLogin = true 更接近真實系統。
2. 身份驗證和授權都要可撤銷
成熟系統要能處理:
- 使用者登出。
- token 失效。
- 密碼被重設。
- 管理員停用帳號。
- 權限被移除。
- 第三方帳號解除綁定。
- 裝置遺失。
如果系統發出去的憑證完全不能撤銷,就要很小心使用場景和過期時間。
3. 安全與體驗要一起設計
安全不是一直要求使用者驗證。
比較好的做法是:
- 低風險操作保持順暢。
- 高風險操作 step-up authentication。
- 新裝置或異常地點提高驗證強度。
- 使用者能管理登入裝置。
- 重要操作有通知與稽核紀錄。
這樣才能在安全與可用性之間取得平衡。
總結
| 問題 | 回答重點 |
|---|---|
| Identity Proofing | 確認使用者身份或聯絡方式可信度 |
| Authentication | 確認這次登入或請求是否可信 |
| Authorization | 確認已登入使用者是否能做某件事 |
| 信箱驗證 | 驗證聯絡方式,不等於完整登入 |
| OAuth / OIDC | OAuth 偏授權,OIDC 提供身份層 |
| 401 / 403 | 401 是未通過身份驗證,403 是已登入但無權限 |
| 前端權限 | 只能改善體驗,後端才是安全邊界 |
一句完整的面試回答可以是:
身份識別、身份驗證和授權要分開看。Identity Proofing 是確認使用者是不是他宣稱的人,例如信箱驗證、手機驗證、自然人憑證;Authentication 是確認這次登入是否可信,例如帳號密碼、Session、TOTP、Passkey;Authorization 是確認已登入使用者能不能做某件事,例如 RBAC、permission、scope 和資料權限。信箱驗證不等於登入,登入成功也不代表有所有權限。401 代表未通過身份驗證或登入狀態失效,403 代表已登入但權限不足。前端可以用路由守衛和按鈕權限改善體驗,但真正的 API 授權和資料權限一定要在後端檢查。