前端身份驗證終極指南:Session、JWT、SSO 和 OAuth 2.0
Hello,大家好,我是 Sunday
在前端項目開發(fā)中,驗證用戶身份主要有 4 種方式:Session、JWT、SSO 和 OAuth 2.0。
那么這四種方式各有什么優(yōu)缺點呢?今天,咱們就來對比下!
01:基于 Session 的經(jīng)典身份驗證方案
什么是基于Session的身份驗證?
基于 Session 的身份驗證是一種在前端和后端系統(tǒng)中常用的用戶認證方法。
它主要依賴于服務器端創(chuàng)建和管理用戶會話。
Session 運行的基本原理
Session 的運行流程分為 6 步:
- 用戶登錄:用戶在登錄頁面輸入憑據(jù)(如用戶名和密碼)。這些憑據(jù)通過前端發(fā)送到后端服務器進行驗證。
- 創(chuàng)建會話:后端服務器驗證憑據(jù)后,創(chuàng)建一個會話(session)。這個會話通常包括一個唯一的會話 ID,該 ID 被存儲在服務器端的會話存儲中。
- 返回會話 ID:服務器將會話 ID 返回給前端,通常是通過設置一個 cookie。這個 cookie 被發(fā)送到用戶的瀏覽器,并在后續(xù)的請求中自動發(fā)送回服務器。
- 保存會話 ID:瀏覽器保存這個 cookie,并在用戶每次向服務器發(fā)起請求時都會自動包含這個 cookie。這樣,服務器就能識別出該用戶的會話,從而實現(xiàn)身份驗證。
- 會話驗證:服務器根據(jù)會話 ID 查找和驗證該用戶的會話信息,并確定用戶的身份。服務器可以使用會話信息來確定用戶的權限和訪問控制。
- 會話過期與管理:服務器可以設置會話過期時間,定期清除過期的會話。用戶注銷或會話超時后,服務器會刪除或使會話失效。
通過以上流程,我們可以發(fā)現(xiàn):基于 Session 的身份驗證,前端是不需要主動參與的。核心是 瀏覽器 和 服務器 進行處理
優(yōu)缺點
優(yōu)點:
- 簡單易用:對開發(fā)者而言,管理會話和驗證用戶身份相對簡單。
- 兼容性好:大多數(shù)瀏覽器支持 cookie,能夠自動發(fā)送和接收 cookie。
缺點:
- 擴展性差:在分布式系統(tǒng)中,多個服務器可能需要共享會話存儲,這可能會增加復雜性。
- 必須配合 HTTPS:如果 cookie 被竊取,可能會導致會話劫持。因此需要使用 HTTPS 來保護傳輸過程中的安全性,并實施其他安全措施(如設置 cookie 的 HttpOnly 和 Secure 屬性)。
示例代碼
接下來,我們通過 Express 實現(xiàn)一個基本的 Session 驗證示例
const express = require('express');
const session = require('express-session');
const app = express();
// 配置和使用 express-session 中間件
app.use(session({
secret: 'your-secret-key', // 用于簽名 Session ID cookie 的密鑰,確保會話的安全
resave: false, // 是否每次請求都重新保存 Session,即使 Session 沒有被修改
saveUninitialized: true, // 是否保存未初始化的 Session
cookie: {
secure: true, // 是否只通過 HTTPS 發(fā)送 cookie,設置為 true 需要 HTTPS 支持
maxAge: 24 * 60 * 60 * 1000 // 設置 cookie 的有效期,這里設置為 24 小時
}
}));
// 登錄路由處理
app.post('/login', (req, res) => {
// 進行用戶身份驗證(這里假設用戶已經(jīng)通過驗證)
// 用戶 ID 應該從數(shù)據(jù)庫或其他存儲中獲取
const user = { id: 123 }; // 示例用戶 ID
req.session.userId = user.id; // 將用戶 ID 存儲到 Session 中
res.send('登錄成功');
});
app.get('/dashboard', (req, res) => {
if (req.session.userId) {
// 如果 Session 中存在用戶 ID,說明用戶已登錄
res.send('返回內(nèi)容...');
} else {
// 如果 Session 中沒有用戶 ID,說明用戶未登錄
res.send('請登錄...'); // 提示用戶登錄
}
});
app.listen(3000, () => {
console.log('服務器正在監(jiān)聽 3000 端口...');
});
02:基于 JWT(JSON Web Token) 的身份驗證方案
什么是基于 JWT 的身份驗證?
這應該是我們目前 最常用 的身份驗證方式。
服務端返回 Token 表示用戶身份令牌。在請求中,把 token 添加到請求頭中,以驗證用戶信息。
因為 HTTP 請求本身是無狀態(tài)的,所以這種方式也被成為是 無狀態(tài)身份驗證方案
JWT 運行的基本原理
- 用戶登錄:用戶在登錄頁面輸入憑據(jù)(如用戶名和密碼),這些憑據(jù)通過前端發(fā)送到后端服務器進行驗證。
- 生成 JWT:后端服務器驗證用戶憑據(jù)后,生成一個 JWT。這個 JWT 通常包含用戶的基本信息(如用戶 ID)和一些元數(shù)據(jù)(如過期時間)。
- 返回 JWT:服務器將生成的 JWT 發(fā)送回前端,通常通過響應的 JSON 數(shù)據(jù)返回。
- 存儲 JWT:前端將 JWT 存儲在客戶端(Token),通常是 localStorage 。極少數(shù)的情況下會保存在 cookie 中(但是需要注意安全風險,如:跨站腳本攻擊(XSS)和跨站請求偽造(CSRF))
- 使用 JWT 進行請求:在用戶進行 API 調(diào)用時,前端將 JWT(Token) 附加到請求的 Authorization 頭部(格式為 Bearer <token>)發(fā)送到服務器。
- 驗證 JWT:服務器接收到請求后,提取 JWT(Token) 并驗證其有效性。驗證過程包括檢查簽名、過期時間等。如果 JWT 合法,服務器會處理請求并返回相應的資源或數(shù)據(jù)。
- 響應請求:服務器處理請求并返回結(jié)果,前端根據(jù)需要展示或處理這些結(jié)果。
優(yōu)缺點
優(yōu)點
- 無狀態(tài):JWT 是自包含的,不需要在服務器端存儲會話信息,簡化了擴展性和負載均衡。
- 跨域支持:JWT 可以在跨域請求中使用(例如,API 與前端分離的場景)。
缺點
- 安全性:JWT 的安全性取決于密鑰的保護和有效期的管理。JWT 一旦被盜用,可能會帶來安全風險。
示例代碼
接下來,我們通過 Express 實現(xiàn)一個基本的 JWT 驗證示例
const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
const secretKey = 'your-secret-key'; // JWT 的密鑰,用于簽名和驗證
// 登錄路由,生成 JWT
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 用戶身份驗證(假設驗證通過)
const user = { id: 1, username: 'user' }; // 示例用戶信息
const token = jwt.sign(user, secretKey, { expiresIn: '24h' }); // 生成 JWT
res.json({ token }); // 返回 JWT
});
// 受保護的路由
app.get('/dashboard', (req, res) => {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).send('沒有提供令牌');
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).send('無效的令牌');
}
res.send('返回儀表板內(nèi)容');
});
});
app.listen(3000, () => {
console.log('服務器正在監(jiān)聽 3000 端口...');
});
03:基于 SSO 的身份驗證方案
什么是基于 SSO(Single Sign-On,單點登錄) 的身份驗證?
SSO 身份驗證多用在 “成套” 的應用程序中,通過 登錄中心 的方式,可以實現(xiàn) 一次登錄,在多個應用中均可以獲取身份
SSO 運行的基本原理
- 用戶訪問應用:用戶訪問一個需要登錄的應用(稱為服務提供者或 SP)。
- 重定向到身份提供者:由于用戶尚未登錄,應用會將用戶重定向到 SSO 身份提供者(Identity Provider,簡稱 IdP)(一般稱為 登錄中心)。登錄中心 是負責處理用戶登錄和身份驗證的系統(tǒng)。
- 用戶登錄:用戶在 登錄中心 輸入憑據(jù)進行登錄。如果用戶已經(jīng)在 IdP 處登錄過(例如,已登錄到公司內(nèi)部的 SSO 系統(tǒng)),則可能直接跳過登錄步驟。
- 生成 SSO 令牌:SSO 身份提供者驗證用戶身份后,生成一個 SSO 令牌(如 OAuth 令牌或 SAML 斷言),并將用戶重定向回原應用,同時附帶令牌。
- 令牌驗證:原應用(服務提供者)接收到令牌后,會將其發(fā)送到 SSO 身份提供者進行驗證。SSO 身份提供者返回用戶的身份信息。
- 用戶訪問應用:一旦身份驗證成功,原應用會根據(jù)用戶的身份信息提供訪問權限。用戶現(xiàn)在可以訪問應用中的受保護資源,而無需再次登錄。
- 訪問其他應用:如果用戶訪問其他應用,這些應用會重定向用戶到相同的 登錄中心 進行身份驗證。由于用戶已經(jīng)登錄,登錄中心 會自動驗證并將用戶重定向回目標應用,從而實現(xiàn)無縫登錄。
優(yōu)缺點
優(yōu)點
- 簡化用戶體驗:用戶只需登錄一次,即可訪問多個應用或系統(tǒng),減少了重復登錄的麻煩。
- 集中管理:管理員可以集中管理用戶的身份和訪問權限,提高了管理效率和安全性。
- 提高安全性:減少了密碼泄露的風險,因為用戶只需記住一個密碼,并且可以使用更強的認證機制(如多因素認證)。
缺點
- 單點故障:如果 登錄中心 出現(xiàn)問題,可能會影響所有依賴該 SSO 服務的應用。
- 復雜性:SSO 解決方案的部署和維護可能較為復雜,需要確保安全配置和互操作性。
常見的 SSO 實現(xiàn)技術
- SAML(Security Assertion Markup Language):
- 一個 XML-based 標準,用于在身份提供者和服務提供者之間傳遞認證和授權數(shù)據(jù)。
- 常用于企業(yè)環(huán)境中的 SSO 實現(xiàn)。
- OAuth 2.0 和 OpenID Connect:
OAuth 2.0 是一種授權框架,用于授權第三方訪問用戶資源。
OpenID Connect 是建立在 OAuth 2.0 之上的身份層,提供用戶身份認證功能。
常用于 Web 和移動應用中的 SSO 實現(xiàn)。
CAS(Central Authentication Service):
一個用于 Web 應用的開源 SSO 解決方案,允許用戶通過一次登錄訪問多個 Web 應用。
04:基于 OAuth 2.0 的身份驗證方案
什么是基于 OAuth 2.0 的身份驗證?
基于 OAuth 2.0 的身份驗證是一種用于授權第三方應用訪問用戶資源的標準協(xié)議。常見的有:微信登錄、QQ 登錄、APP 掃碼登錄等
OAuth 2.0 主要用于授權,而不是身份驗證,但通常與身份驗證結(jié)合使用來實現(xiàn)用戶登錄功能。
OAuth 2.0 運行的基本原理
OAuth 2.0 比較復雜,在了解它的原理之前,我們需要先明確一些基本概念。
OAuth 2.0 的基本概念
- 資源擁有者(Resource Owner):通常是用戶,擁有需要保護的資源(如個人信息、文件等)。
- 資源服務器(Resource Server):提供資源的服務器,需要保護這些資源免受未經(jīng)授權的訪問。
- 客戶端(Client):需要訪問資源的應用程序或服務??蛻舳诵枰@得資源擁有者的授權才能訪問資源。
- 授權服務器(Authorization Server):責認證資源擁有者并授權客戶端訪問資源。它頒發(fā)訪問令牌(Access Token)給客戶端,允許客戶端訪問資源服務器上的受保護資源。
運行原理
- 用戶授權:用戶使用客戶端應用進行操作時,客戶端會請求授權訪問用戶的資源。用戶會被重定向到授權服務器進行授權。
- 獲取授權碼(Authorization Code):如果用戶同意授權,授權服務器會生成一個授權碼,并將其發(fā)送回客戶端(通過重定向 URL)。
- 獲取訪問令牌(Access Token):客戶端使用授權碼向授權服務器請求訪問令牌。授權服務器驗證授權碼,并返回訪問令牌。
- 訪問資源:客戶端使用訪問令牌向資源服務器請求訪問受保護的資源。資源服務器驗證訪問令牌,并返回請求的資源。
常見的授權流程
- 授權碼流程(Authorization Code Flow):最常用的授權流程,適用于需要與用戶交互的客戶端(如 Web 應用)。用戶在授權服務器上登錄并授權,客戶端獲取授權碼后再交換訪問令牌。
- 隱式流程(Implicit Flow):適用于公共客戶端(如單頁應用)。用戶直接獲得訪問令牌,適用于不需要安全存儲的情況,但不推薦用于高度安全的應用。
- 資源所有者密碼憑據(jù)流程(Resource Owner Password Credentials Flow):適用于信任客戶端的情況。用戶直接將用戶名和密碼提供給客戶端,客戶端直接獲得訪問令牌。這種流程不推薦用于公開的客戶端。
- 客戶端憑據(jù)流程(Client Credentials Flow):適用于機器對機器的情況。客戶端直接向授權服務器請求訪問令牌,用于訪問與客戶端本身相關的資源。
優(yōu)缺點
優(yōu)點
- 靈活性:OAuth 2.0 支持多種授權流程,適應不同類型的客戶端和應用場景。
- 安全性:通過分離授權和認證,增強了系統(tǒng)的安全性。使用令牌而不是用戶名密碼來訪問資源。
缺點
- 復雜性:OAuth 2.0 的實現(xiàn)和配置可能較復雜,需要正確管理訪問令牌和刷新令牌。
- 安全風險:如果令牌泄露,可能會導致安全風險。因此需要采取適當?shù)陌踩胧ㄈ缡褂?HTTPS 和適當?shù)牧钆乒芾聿呗裕?/li>
示例代碼
接下來,我們通過 Express 實現(xiàn)一個基本的 OAuth 2.0 驗證示例
const express = require('express');
const axios = require('axios');
const app = express();
// OAuth 2.0 配置
const clientId = 'your-client-id';
const clientSecret = 'your-client-secret';
const redirectUri = 'http://localhost:3000/callback';
const authorizationServerUrl = 'https://authorization-server.com';
const resourceServerUrl = 'https://resource-server.com';
// 登錄路由,重定向到授權服務器
app.get('/login', (req, res) => {
const authUrl = `${authorizationServerUrl}/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=read`;
res.redirect(authUrl);
});
// 授權回調(diào)路由,處理授權碼
app.get('/callback', async (req, res) => {
const { code } = req.query;
if (!code) {
return res.status(400).send('Authorization code is missing');
}
try {
// 請求訪問令牌
const response = await axios.post(`${authorizationServerUrl}/token`, {
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret
});
const { access_token } = response.data;
// 使用訪問令牌訪問資源
const resourceResponse = await axios.get(`${resourceServerUrl}/user-info`, {
headers: { Authorization: `Bearer ${access_token}` }
});
res.json(resourceResponse.data);
} catch (error) {
res.status(500).send('Error during token exchange or resource access');
}
});
app.listen(3000, () => {
console.log('服務器正在監(jiān)聽 3000 端口...');
});
總結(jié)一下
目前這四種驗證方案均有對應的 優(yōu)缺點、應用場景:
- Session:非常適合簡單的服務器呈現(xiàn)的應用程序
- JWT:適用于現(xiàn)代無狀態(tài)架構(gòu)和移動應用
- SSO:非常適合具有多種相關服務的企業(yè)環(huán)境
- OAuth 2.0:第三方集成和 API 訪問的首選