目錄
1.前言
2.正文
2.1Cookie—Session機制
2.1.1核心原理圖解:
2.1.2四步核心流程:
2.1.3存儲架構對比
2.1.4集群部署方案(Spring Session + Redis)
2.2Token令牌
2.2.1核心原理圖解:
2.2.2四步核心流程:
2.2.3安全架構設計
2.3JWT令牌驗證
2.3.1核心原理圖解:
2.3.2JWT結構
2.3.3安全風險與解決方案
2.3.4簽名算法對比
2.4三種方案對比
2.4.1核心機制對比表
2.4.2安全性與控制力對比
2.4.3性能與擴展性對比
2.4.4開發復雜度對比
2.4.5典型應用場景推薦
3.小結
1.前言
登錄認證是系統安全的門戶,而會話的持續管理策略直接影響開發效率與系統健壯性。許多開發者在實踐中常陷入困惑:
-
為何Session在集群部署時突然失效?
-
Token與JWT看似相似,核心差異究竟在哪?
-
如何避免常見的安全陷阱?
本文針對主流場景,從底層原理剖析Session、Token、JWT三大用戶校驗方案,結合Java代碼實現與安全規范,詳解其工作機制、適用邊界及落地要點。無論您是構建傳統Web應用還是前后端分離項目,均可獲得可直接復用的實踐方案。
插播一條消息~
🔍?十年經驗淬煉 · 系統化AI學習平臺推薦
系統化學習AI平臺https://www.captainbed.cn/scy/
- 📚 完整知識體系:從數學基礎 → 工業級項目(人臉識別/自動駕駛/GANs),內容由淺入深
- 💻 實戰為王:每小節配套可運行代碼案例(提供完整源碼)
- 🎯 零基礎友好:用生活案例講解算法,無需擔心數學/編程基礎
🚀 特別適合
- 想系統補強AI知識的開發者
- 轉型人工智能領域的從業者
- 需要項目經驗的學生
2.正文
在正式講解常見的登錄驗證方式,先看看無驗證的登陸流程是怎樣的。
核心邏輯:
致命缺陷:
1.零身份驗證
- 攻擊者輸入任意有效用戶名(無需密碼)即可登錄他人賬戶。
- 示例:輸入?
admin
?直接獲取管理員權限。
2.會話劫持風險
- 未登錄用戶訪問?
/profile
?接口導致空指針異常(無用戶信息)。- 若會話ID被竊取(如XSS攻擊),攻擊者可直接復用會話。
3.越權操作
- 用戶A登錄后,修改URL參數即可操作用戶B的數據(如?
/deleteUser?id=2
)。
2.1Cookie—Session機制
2.1.1核心原理圖解:
2.1.2四步核心流程:
-
會話創建階段
-
用戶提交有效憑證(用戶名+密碼)
-
服務端驗證通過后:
// Java Servlet示例 HttpSession session = request.getSession(true); // 創建新會話 session.setAttribute("user", userObject); // 存儲用戶對象 session.setMaxInactiveInterval(30*60); // 設置30分鐘超時
-
生成唯一Session ID(如JSESSIONID)
-
-
Cookie傳遞階段
-
服務端響應頭包含:
HTTP/1.1 200 OK Set-Cookie: JSESSIONID=5A8C3D9F1E7B2; Path=/; HttpOnly; Secure; SameSite=Lax
-
關鍵屬性:
-
HttpOnly
:阻止JavaScript訪問 -
Secure
:僅HTTPS傳輸 -
SameSite
:防御CSRF攻擊
-
-
-
會話保持階段
-
客戶端后續請求自動攜帶Cookie:
GET /profile HTTP/1.1 Cookie: JSESSIONID=5A8C3D9F1E7B2
-
服務端校驗流程:
public boolean checkSession(HttpServletRequest request) {HttpSession session = request.getSession(false); // 不創建新會話if(session == null) {return false; // 會話不存在}User user = (User)session.getAttribute("user");return user != null; // 用戶對象存在 }
-
-
會話銷毀階段
-
主動注銷:
session.invalidate(); // 立即銷毀會話
-
超時銷毀(web.xml配置):
<session-config><session-timeout>30</session-timeout> <!-- 單位:分鐘 --> </session-config>
-
2.1.3存儲架構對比
存儲方式 | 實現方案 | 優點 | 缺點 |
---|---|---|---|
內存存儲 | Web容器默認(Tomcat等) | 零配置、響應快 | 單點故障、集群失效 |
Redis存儲 | Spring Session + Redis | 分布式支持、高性能 | 需額外中間件 |
數據庫存儲 | 自定義Session表 | 持久化可靠、數據完整 | 性能低、需清理機制 |
文件存儲 | 序列化到文件系統 | 簡單易實現 | I/O瓶頸、擴展性差 |
2.1.4集群部署方案(Spring Session + Redis)
-
依賴配置
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId> </dependency>
-
配置類
@EnableRedisHttpSession public class SessionConfig {@Beanpublic LettuceConnectionFactory connectionFactory() {return new LettuceConnectionFactory(); } }
-
會話存取原理
Cookie-Session機制在傳統Web應用中保持不可替代地位,通過嚴格的會話管理策略和集群擴展方案,可構建安全可靠的用戶認證體系。?
2.2Token令牌
2.2.1核心原理圖解:
2.2.2四步核心流程:
1. Token生成階段
// 生成強隨機Token(示例)
public String generateToken() {// 使用SecureRandom保證加密強度SecureRandom random = new SecureRandom();byte[] bytes = new byte[32];random.nextBytes(bytes);return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}// 存儲關聯關系(Redis示例)
public void storeToken(String token, User user) {// 設置Token有效期(如2小時)redisTemplate.opsForValue().set("AUTH_TOKEN:" + token, user.getId(),2, TimeUnit.HOURS);
}
2. Token傳遞方式
傳遞方式 | 實現示例 | 適用場景 |
---|---|---|
Header傳遞 |
| 前后端分離項目(主流) |
URL參數 |
| 臨時調試(不安全) |
POST Body |
| 特殊接口場景 |
Cookie存儲 |
| 兼容傳統Web應用 |
3. 服務端驗證流程
// Token驗證攔截器
public class TokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. 從Header獲取TokenString token = request.getHeader("Authorization");if(token == null || !token.startsWith("Bearer ")) {response.setStatus(401);return false;}token = token.substring(7);// 2. 查詢Redis驗證String userId = redisTemplate.opsForValue().get("AUTH_TOKEN:" + token);if(userId == null) {response.setStatus(401);return false;}// 3. 加載用戶數據User user = userService.findById(userId);if(user == null) {response.setStatus(401);return false;}// 4. 設置安全上下文SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()));return true;}
}
4. Token注銷機制
// 主動注銷
@PostMapping("/logout")
public ResponseEntity logout(@RequestHeader("Authorization") String token) {token = token.replace("Bearer ", "");redisTemplate.delete("AUTH_TOKEN:" + token);return ResponseEntity.ok().build();
}// 自動過期(依賴Redis TTL)
// 可通過定時任務清理過期Token
2.2.3安全架構設計
1. 防御令牌劫持
攻擊類型 | 防御措施 | 實現方案 |
---|---|---|
XSS攻擊 | HttpOnly Cookie存儲 | Set-Cookie: token=xyz; HttpOnly |
中間人攻擊 | 強制HTTPS傳輸 | 服務端校驗請求協議 |
CSRF攻擊 | 校驗Origin頭+CORS策略 | response.setHeader("Access-Control-Allow-Origin", "trusted.com") |
2. 令牌綁定策略
// 設備指紋綁定
public String generateDeviceFingerprint(HttpServletRequest req) {String ip = req.getRemoteAddr();String userAgent = req.getHeader("User-Agent");return DigestUtils.sha256Hex(ip + userAgent);
}// 存儲時綁定
redisTemplate.opsForValue().set("AUTH_TOKEN:" + token, user.getId() + "|" + deviceFingerprint, 2, TimeUnit.HOURS
);// 驗證時檢查
String[] parts = storedValue.split("\\|");
if(!parts[1].equals(currentDeviceFingerprint)) {// 異常設備訪問,強制注銷redisTemplate.delete("AUTH_TOKEN:" + token);return false;
}
Token機制為現代分布式架構提供了靈活的身份驗證方案。通過嚴格的密鑰管理、傳輸加密和存儲安全措施,可構建高性能、可擴展的認證體系,特別適合API驅動的前后端分離應用。
2.3JWT令牌驗證
2.3.1核心原理圖解:
2.3.2JWT結構
JWT由三部分組成,以點分隔:Header.Payload.Signature
1. Header(頭部)
{"alg": "HS256", // 簽名算法(HS256/RSA等)"typ": "JWT" // 令牌類型 }
Base64Url編碼后形成第一部分
2. Payload(載荷)
{"sub": "1234567890", // 標準聲明(subject)"name": "John Doe", // 自定義聲明"iat": 1516239022, // 簽發時間(issued at)"exp": 1516239322 // 過期時間(expiration) }
標準聲明字段:
字段 全稱 說明 iss Issuer 簽發者 sub Subject 主題(用戶ID) aud Audience 接收方 exp Expiration Time 過期時間(時間戳) nbf Not Before 生效時間(時間戳) iat Issued At 簽發時間(時間戳) jti JWT ID 唯一標識(防重放)
3. Signature(簽名)
// 偽代碼示例 signature = HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secretKey )
防止數據篡改的核心保障
算法可選:HS256(對稱)/ RS256(非對稱)
代碼實現:
1. 生成JWT
// 依賴
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtime 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtime 'io.jsonwebtoken:jjwt-jackson:0.11.5'// 生成代碼
String secretKey = "your-256-bit-secret"; // 實際應使用安全隨機生成String jwt = Jwts.builder().setSubject("user123") // 用戶標識.claim("name", "John Doe") // 自定義聲明.claim("role", "ADMIN").setIssuedAt(new Date()) // 簽發時間.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小時過期.signWith(SignatureAlgorithm.HS256, secretKey) // 簽名算法.compact();
2. 驗證JWT
public boolean validateToken(String jwt) {try {Claims claims = Jwts.parserBuilder().setSigningKey(secretKey) // 設置密鑰.build().parseClaimsJws(jwt) // 解析并驗證簽名.getBody();// 手動校驗過期時間(庫自動校驗exp,此處演示邏輯)Date expiration = claims.getExpiration();if(expiration.before(new Date())) {throw new ExpiredJwtException(null, claims, "Token expired");}// 獲取用戶信息String username = claims.getSubject();String role = claims.get("role", String.class);return true;} catch (JwtException e) {// 處理各種異常:簽名無效/過期/格式錯誤等return false;}
}
2.3.3安全風險與解決方案
1. 令牌泄露風險
問題:JWT一旦泄露,在有效期內可被濫用
解決方案:
// 短有效期Access Token + 長有效期Refresh Token String accessToken = generateToken(30 * 60); // 30分鐘 String refreshToken = generateToken(7 * 24 * 60 * 60); // 7天// 服務端存儲Refresh Token(Redis) redisTemplate.opsForValue().set("REFRESH:" + userId, refreshToken, 7, TimeUnit.DAYS );
2. 無法即時注銷
問題:服務端無法主動使JWT失效
解決方案:
// 令牌黑名單(短期) @PostMapping("/logout") public void logout(@RequestHeader("Authorization") String token) {token = token.replace("Bearer ", "");long exp = getExpirationFromToken(token); // 從JWT提取過期時間long ttl = exp - System.currentTimeMillis() / 1000;if(ttl > 0) {// 將未過期的Token加入黑名單redisTemplate.opsForValue().set("BLACKLIST:" + token, "revoked", ttl, TimeUnit.SECONDS);} }// 驗證時檢查黑名單 if(redisTemplate.hasKey("BLACKLIST:" + token)) {throw new JwtException("Token revoked"); }
3. 敏感數據暴露
問題:Payload數據可被Base64解碼查看
解決方案:
// 方案1:僅存儲用戶ID .setSubject("user123")// 方案2:使用JWE加密(JSON Web Encryption) String jwe = Jwts.builder().setSubject("user123").encryptWith(Key, keyAlg, encAlg) // 加密配置.compact();
2.3.4簽名算法對比
算法類型 | 代表算法 | 密鑰要求 | 適用場景 |
---|---|---|---|
對稱 | HS256 | 服務端保存相同密鑰 | 內部服務、單點部署 |
非對稱 | RS256 | 私鑰簽名/公鑰驗證 | 多系統集成、開放平臺 |
現代 | EdDSA | 高效橢圓曲線簽名 | 高安全性要求場景 |
JWT為分布式系統提供了無狀態身份驗證方案,通過標準化結構實現跨語言/跨平臺支持。在實施時必須配合短有效期、HTTPS傳輸、黑名單機制等安全措施,才能發揮其最大價值。
2.4三種方案對比
2.4.1核心機制對比表
對比維度 | Session-Cookie | 自定義Token | JWT |
---|---|---|---|
工作原理 | 服務端存儲會話狀態 客戶端存Session ID | 服務端存儲Token-用戶映射 客戶端存Token | 無狀態令牌 自包含簽名驗證 |
狀態管理 | 有狀態(服務端存儲) | 有狀態(服務端存儲) | 無狀態(服務端不存儲) |
數據結構 | 會話ID(通常128bit) | 隨機字符串(通常32-64字節) | 結構化JSON(Header.Payload.Signature) |
客戶端存儲 | Cookie(自動管理) | LocalStorage/手動管理 | LocalStorage/手動管理 |
傳輸方式 | 自動Cookie頭 | 手動Authorization頭 | 手動Authorization頭 |
典型應用場景 | 傳統Web應用(JSP/Thymeleaf) | 前后端分離API服務 | 微服務/跨域認證/SSO |
2.4.2安全性與控制力對比
安全特性 | Session-Cookie | 自定義Token | JWT |
---|---|---|---|
CSRF防護 | ? 需額外Anti-CSRF Token | ? 天然免疫 | ? 天然免疫 |
XSS防護 | ? HttpOnly Cookie | ? LocalStorage易受XSS攻擊 | ? LocalStorage易受XSS攻擊 |
令牌泄露影響 | 中(會話可即時終止) | 中(可刪除服務端Token) | 高(有效期無法提前終止) |
數據暴露風險 | 低(僅ID在客戶端) | 低(僅標識符在客戶端) | 中高(Payload可解碼查看) |
即時注銷能力 | ??session.invalidate() | ? 刪除Redis記錄 | ? 需額外黑名單機制 |
防重放攻擊 | ? 需額外措施 | ? 綁定設備指紋 | ? JTI聲明+短期有效期 |
2.4.3性能與擴展性對比
性能指標 | Session-Cookie | 自定義Token | JWT |
---|---|---|---|
服務端開銷 | 會話存儲查詢(內存/Redis) | Token存儲查詢(Redis) | 僅簽名驗證(無存儲查詢) |
網絡開銷 | 低(僅傳Session ID) | 中(傳完整Token) | 高(傳完整JWT,體積最大) |
集群擴展 | 需Session共享(如Redis) | 需Token存儲共享 | 完美支持(無狀態設計) |
跨域支持 | ? 需復雜CORS配置 | ? 簡單CORS配置 | ? 簡單CORS配置 |
移動端適配 | 困難(Cookie管理問題) | 優秀 | 優秀 |
第三方集成 | 困難 | 中等 | 優秀(標準化格式) |
2.4.4開發復雜度對比
開發環節 | Session-Cookie | 自定義Token | JWT |
---|---|---|---|
服務端實現 | 簡單(框架原生支持) | 中等(需自建驗證邏輯) | 復雜(密鑰管理/黑名單/Refresh機制) |
前端集成 | 零配置(瀏覽器自動管理) | 手動存儲/攜帶Token | 手動存儲/攜帶JWT |
分布式會話 | 復雜(需Spring Session等) | 簡單(Redis直連) | 無需實現 |
調試難度 | 低(Cookie可見) | 中(需查看網絡請求) | 高(需解析JWT內容) |
標準規范 | 無 | 無 | RFC 7519標準 |
2.4.5典型應用場景推薦
場景 | 推薦方案 | 原因說明 |
---|---|---|
傳統企業OA系統 | Session-Cookie | 內部網絡環境安全,需嚴格會話控制,多頁面跳轉體驗流暢 |
電商平臺(前后端分離) | 自定義Token | 需兼顧API性能和移動端支持,高頻查詢需要快速驗證 |
微服務架構 | JWT | 服務間無狀態通信,避免會話共享瓶頸,網關統一認證 |
第三方開放平臺 | JWT + OAuth2 | 標準化令牌格式,合作伙伴系統可自主驗證 |
高安全金融系統 | Session + 雙因素認證 | 需要即時會話終止能力,配合生物識別等強認證手段 |
物聯網設備認證 | JWT(RS256) | 設備資源有限,非對稱簽名降低服務端壓力,長期有效減少驗證頻率 |
3.小結
用戶校驗機制的選擇本質是安全性、擴展性與開發成本的三角博弈:
-
傳統Session方案在服務端強狀態控制場景仍具優勢,但需通過Spring Session+Redis解決分布式一致性痛點;
-
自定義Token以服務端存儲換取架構靈活性,是RESTful API服務的均衡之選;
-
JWT的無狀態特性天然契合微服務,但必須通過“短時效Access Token+服務端管控的Refresh Token”組合彌補注銷缺陷;
無論何種方案,HTTPS傳輸、敏感數據脫敏、憑證安全存儲是必須堅守的底線。技術決策應始于架構訴求,終于安全實踐,方能在業務迭代中構建穩固的認證基石。
今天的分享到這里就結束了,喜歡的小伙伴點點贊點點關注,你的支持就是對我最大的鼓勵,大家加油!