JWT(JSON Web Token)是一種用于在網(wǎng)絡(luò)應(yīng)用環(huán)境中進(jìn)行身份認(rèn)證和信息交換的開(kāi)放標(biāo)準(zhǔn)(RFC 7519)。它以緊湊、獨(dú)立和可驗(yàn)證的方式將信息傳遞給客戶端與服務(wù)器之間,常用于用戶身份認(rèn)證和授權(quán)管理。小編將詳細(xì)介紹JWT的認(rèn)證原理、如何使用JWT進(jìn)行身份認(rèn)證以及如何在實(shí)際項(xiàng)目中實(shí)現(xiàn)JWT認(rèn)證。
一、JWT認(rèn)證的原理
JWT認(rèn)證的核心原理是通過(guò)客戶端和服務(wù)器之間的token來(lái)標(biāo)識(shí)用戶身份??蛻舳嗽诘卿洉r(shí)通過(guò)用戶名和密碼進(jìn)行身份驗(yàn)證,服務(wù)器通過(guò)驗(yàn)證這些信息后生成一個(gè)JWT并返回給客戶端,客戶端保存該JWT并在每次請(qǐng)求時(shí)將其發(fā)送給服務(wù)器進(jìn)行驗(yàn)證。服務(wù)器驗(yàn)證JWT的有效性后,允許或拒絕客戶端的請(qǐng)求。
JWT由三部分組成:
頭部(Header):描述JWT的元數(shù)據(jù),通常包含兩部分信息:類型(JWT)和加密算法(如HMAC SHA256)。
負(fù)載(Payload):存儲(chǔ)需要傳遞的數(shù)據(jù),如用戶信息、過(guò)期時(shí)間等。負(fù)載部分的數(shù)據(jù)是未加密的,所以不適合存儲(chǔ)敏感數(shù)據(jù)。
簽名(Signature):通過(guò)加密算法對(duì)頭部和負(fù)載部分進(jìn)行加密,確保JWT在傳輸過(guò)程中不會(huì)被篡改。
JWT的結(jié)構(gòu)示例如下:
Copy Codeheader.payload.signature
1. 頭部(Header)
頭部一般由兩部分組成:令牌的類型(JWT)和所使用的簽名算法(如HMAC SHA256 或 RSA)。
示例:
jsonCopy Code{
"alg": "HS256",
"typ": "JWT"
}
2. 負(fù)載(Payload)
負(fù)載部分存儲(chǔ)的是JWT中要傳遞的聲明(Claims)。聲明通常分為三種類型:
注冊(cè)聲明(Registered Claims):如 iss(發(fā)行者)、exp(過(guò)期時(shí)間)、sub(主題)等。
公共聲明(Public Claims):自定義字段,可以用于交換信息。
私有聲明(Private Claims):自定義聲明字段,只有JWT的創(chuàng)建者和使用者知曉。
例如:
jsonCopy Code{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
3. 簽名(Signature)
簽名用于驗(yàn)證JWT數(shù)據(jù)的完整性以及消息的來(lái)源。簽名是通過(guò)以下方式生成的:
Copy CodeHMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
其中,secret是服務(wù)器保存的密鑰,用于簽名和驗(yàn)證簽名。只有服務(wù)器知道該密鑰,其他人無(wú)法偽造有效的JWT。

二、JWT認(rèn)證的工作流程
JWT認(rèn)證的整個(gè)過(guò)程通常包括以下幾個(gè)步驟:
1. 用戶登錄
用戶通過(guò)用戶名和密碼進(jìn)行登錄,服務(wù)器驗(yàn)證用戶的身份,確認(rèn)無(wú)誤后生成JWT并返回給客戶端。這個(gè)JWT包含了用戶的身份信息以及有效期等聲明。
2. 客戶端存儲(chǔ)JWT
客戶端接收到JWT后,通常將其存儲(chǔ)在本地存儲(chǔ)(localStorage)或者會(huì)話存儲(chǔ)(sessionStorage)中。注意,JWT不應(yīng)該存儲(chǔ)在瀏覽器的cookie中,避免XSS攻擊。
3. 客戶端攜帶JWT請(qǐng)求服務(wù)器
客戶端在后續(xù)的每次請(qǐng)求中,將JWT放入HTTP請(qǐng)求的Authorization頭部,格式如下:
Copy CodeAuthorization: Bearer <JWT>
4. 服務(wù)器驗(yàn)證JWT
服務(wù)器接收到請(qǐng)求后,從請(qǐng)求頭部提取JWT,并驗(yàn)證其合法性。驗(yàn)證的過(guò)程包括:
檢查JWT是否存在;
檢查JWT的簽名是否正確;
檢查JWT是否已過(guò)期;
檢查JWT中聲明的其他信息是否有效。
如果JWT有效,服務(wù)器根據(jù)JWT中的用戶信息為用戶提供服務(wù)。如果無(wú)效,服務(wù)器會(huì)返回401 Unauthorized錯(cuò)誤。
5. 返回響應(yīng)
如果JWT有效,服務(wù)器處理完請(qǐng)求后返回響應(yīng);如果無(wú)效,返回錯(cuò)誤信息。
三、如何使用JWT進(jìn)行身份認(rèn)證
1. 生成JWT
在用戶登錄時(shí),服務(wù)器會(huì)根據(jù)用戶的身份信息生成JWT,簽名時(shí)使用一個(gè)密鑰(secret)以確保安全性。
下面是一個(gè)使用Node.js生成JWT的示例代碼:
javascriptCopy Codeconst jwt = require('jsonwebtoken');
// 用戶的身份信息
const user = {
id: 1,
username: 'john_doe'
};
// 秘鑰(用于簽名和驗(yàn)證)
const secretKey = 'mysecretkey';
// 生成JWT,設(shè)置過(guò)期時(shí)間為1小時(shí)
const token = jwt.sign(user, secretKey, { expiresIn: '1h' });
console.log('Generated JWT:', token);
在上面的代碼中,jwt.sign()方法用于生成JWT,第一個(gè)參數(shù)是負(fù)載數(shù)據(jù)(如用戶ID、用戶名等),第二個(gè)參數(shù)是密鑰,第三個(gè)參數(shù)是可選的配置項(xiàng),如過(guò)期時(shí)間。
2. 驗(yàn)證JWT
每次用戶請(qǐng)求時(shí),服務(wù)器會(huì)驗(yàn)證JWT的有效性,確保它沒(méi)有被篡改且未過(guò)期。下面是驗(yàn)證JWT的代碼示例:
javascriptCopy Codeconst jwt = require('jsonwebtoken');
// 獲取請(qǐng)求頭中的JWT
const token = req.headers['authorization'].split(' ')[1];
// 驗(yàn)證JWT
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).send('Invalid or expired token');
}
// 如果JWT有效,返回解碼后的用戶信息
req.user = decoded;
next(); // 繼續(xù)處理請(qǐng)求
});
在這段代碼中,jwt.verify()用于驗(yàn)證JWT的合法性。如果JWT有效,decoded將包含JWT的負(fù)載數(shù)據(jù)(如用戶ID等);如果無(wú)效或過(guò)期,則返回401 Unauthorized錯(cuò)誤。
3. 使用JWT中間件
為了簡(jiǎn)化JWT驗(yàn)證過(guò)程,可以封裝一個(gè)JWT驗(yàn)證中間件,集中處理身份認(rèn)證邏輯。
javascriptCopy Codefunction authenticateJWT(req, res, next) {
const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
if (!token) {
return res.status(403).send('A token is required for authentication');
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).send('Invalid or expired token');
}
req.user = decoded; // 將解碼后的用戶信息掛載到請(qǐng)求對(duì)象上
next();
});
}
在路由中使用中間件:
javascriptCopy Codeapp.get('/protected', authenticateJWT, (req, res) => {
res.send('This is a protected route');
});
這樣,當(dāng)用戶訪問(wèn) /protected 路由時(shí),authenticateJWT 中間件會(huì)先驗(yàn)證JWT的合法性,只有通過(guò)驗(yàn)證后才會(huì)繼續(xù)處理請(qǐng)求。
四、JWT認(rèn)證的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
無(wú)狀態(tài)(Stateless):JWT不需要在服務(wù)器端存儲(chǔ)會(huì)話信息,減少了服務(wù)器的存儲(chǔ)負(fù)擔(dān)。所有的認(rèn)證信息都存儲(chǔ)在JWT本身。
跨域支持:JWT支持跨域認(rèn)證,適用于微服務(wù)架構(gòu)或單頁(yè)面應(yīng)用(SPA)。
靈活性:JWT可以在負(fù)載中存儲(chǔ)任意的自定義數(shù)據(jù),增加了靈活性。
缺點(diǎn):
安全性問(wèn)題:JWT本身是未加密的,因此不適合存儲(chǔ)敏感信息(如密碼),如果攻擊者獲取了JWT,它就能夠偽造請(qǐng)求。
令牌失效:由于JWT是無(wú)狀態(tài)的,一旦生成,直到過(guò)期前它一直有效,不能立即撤銷。如果需要強(qiáng)制注銷用戶,需要特殊的處理(如使用黑名單)。
JWT是一種簡(jiǎn)潔、安全且高效的身份認(rèn)證方式,尤其適用于分布式架構(gòu)和無(wú)狀態(tài)的應(yīng)用。通過(guò)理解JWT的工作原理,結(jié)合實(shí)際需求,可以輕松實(shí)現(xiàn)基于JWT的身份認(rèn)證系統(tǒng)。然而,在實(shí)現(xiàn)JWT認(rèn)證時(shí),開(kāi)發(fā)者需要注意安全性,特別是JWT的存儲(chǔ)和簽名的保護(hù)。