SpringBoot Cookie & Session 用戶登錄及登錄狀態(tài)保持功能實(shí)現(xiàn)代碼
會(huì)話技術(shù)
- 功能:提供用戶登陸成功后的登陸標(biāo)記 (一次登錄,一段時(shí)間都登錄)
- 會(huì)話
- 定義:包含一次或多次請(qǐng)求和響應(yīng)的訪問(wèn)操作
- 建立會(huì)話:用戶打開瀏覽器訪問(wèn) Web 服務(wù)器資源時(shí)建立會(huì)話
- 結(jié)束會(huì)話:一方斷開連接時(shí)結(jié)束會(huì)話
- 會(huì)話跟蹤
- 定義:一種維護(hù)瀏覽器狀態(tài)的方法
- 功能:服務(wù)器通過(guò)會(huì)話跟蹤來(lái)識(shí)別多次請(qǐng)求是否來(lái)自于同一瀏覽器
- 同一次會(huì)話的多次請(qǐng)求間共享數(shù)據(jù)
- 會(huì)話跟蹤方案
客戶端會(huì)話跟蹤技術(shù) : Cookie

服務(wù)端會(huì)話跟蹤技術(shù) : Session

令牌技術(shù)(token)
令牌 : 用戶身份的標(biāo)識(shí),實(shí)際上就是一個(gè)字符串
Cookie
定義:瀏覽器訪問(wèn)服務(wù)器后,服務(wù)器傳給瀏覽器的一段數(shù)據(jù),由瀏覽器保存,后續(xù)通信中瀏覽器也要將 Cookie 發(fā)送給服務(wù)器功能- 識(shí)別用戶身份 (uid)
- 存儲(chǔ)用戶偏好:讓瀏覽器記住這位訪客的特定信息
工作條件- 瀏覽器每次訪問(wèn)該服務(wù)器,都必須帶上 Cookie
- 瀏覽器需要保存 Cookie,不得輕易刪除
- 不能跨域
工作流程- 客戶端提交一個(gè)HTTP請(qǐng)求給服務(wù)端
- 服務(wù)端 Set-Cookie,同時(shí)提交響應(yīng)內(nèi)容給客戶端
- 客戶端再次向服務(wù)器請(qǐng)求,并在請(qǐng)求頭中攜帶一個(gè)Cookie
有效期- Expire 值:Cookie 在生成時(shí)就會(huì)被指定一個(gè) Expire 值,這就是 Cookie 的生存周期
- 立即清除 Cookie:生存周期設(shè)置為 “0” 或負(fù)值,這樣在關(guān)閉瀏覽器時(shí),就馬上清除 Cookie,不會(huì)記錄用戶信息,更加安全
缺點(diǎn)- 數(shù)量限制:一個(gè)瀏覽器能創(chuàng)建的 Cookie 數(shù)量最多為 300 個(gè),并且每個(gè)不能超過(guò) 4KB,每個(gè) Web 站點(diǎn)能設(shè)置的 Cookie 總數(shù)不能超過(guò) 20 個(gè)
- 安全性低:存在跨站點(diǎn)腳本攻擊的可能,腳本指令可以讀取當(dāng)前站點(diǎn)的所有 Cookie 內(nèi)容,并且可以提交到指定服務(wù)器重現(xiàn)其功能
問(wèn):為什么需要 Cookie 答:web程序使用的HTTP協(xié)議是無(wú)狀態(tài)的協(xié)議,對(duì)于事務(wù)處理沒(méi)有記憶能力,如果后續(xù)處理需要前面的信息則必須重傳,導(dǎo)致每次連接傳送的數(shù)據(jù)量增大
Session
一、概述
定義- Session (會(huì)話控制),Session 對(duì)象存儲(chǔ)特定用戶會(huì)話所需的屬性及配置信息
- SessionID:客戶端第一次請(qǐng)求服務(wù)器時(shí),服務(wù)器為客戶端算出的一個(gè)值,存儲(chǔ)在 Cookie 中,用于定位用戶 Session 在服務(wù)器中的位置
- 與 Cookie 的區(qū)別:Cookie 可以通過(guò)偽造來(lái)實(shí)現(xiàn)登錄并進(jìn)行一些 HTTP 請(qǐng)求,從安全性上來(lái)講,Session 比 Cookie 安全性稍微高一些
功能:提高安全性有效期:一般為半小時(shí),可以根據(jù)需求設(shè)定缺點(diǎn):Session 是存儲(chǔ)在服務(wù)器當(dāng)中的,所以 Session 過(guò)多,會(huì)對(duì)服務(wù)器產(chǎn)生壓力
二、相關(guān)工具類
HttpSession- 定義:javax.servlet.http.HttpSession 類,是 JavaWeb 自帶的工具類
- 常用方法
- 命令
- 功能
- getAttribute(“attributeName”)
- 獲取指定名稱的屬性值
- setAttribute(“attributeName”, myAttributeObject)
- 設(shè)置指定名稱的屬性值
DTO:Data Transfer Object,在 Session 中的 MyClass 應(yīng)該去掉敏感信息,轉(zhuǎn)為 MyClassDTO 進(jìn)行傳輸
三、認(rèn)證流程
工作流程
- 創(chuàng)建 Session :用戶第一次請(qǐng)求服務(wù)器的時(shí)候,服務(wù)器根據(jù)用戶提交的相關(guān)信息,創(chuàng)建對(duì)應(yīng)的 Session
- 響應(yīng) Session ID:服務(wù)器響應(yīng)請(qǐng)求時(shí),將此 Session 的唯一標(biāo)識(shí)信息 SessionID 返回給瀏覽器
- 存入 Cookie:瀏覽器接收到服務(wù)器返回的 SessionID 信息后,將此信息存入到 Cookie 中,同時(shí) Cookie 記錄此 SessionID 屬于哪個(gè)域名
- 攜帶 Cookie:當(dāng)用戶第二次訪問(wèn)服務(wù)器的時(shí)候,請(qǐng)求會(huì)自動(dòng)判斷此域名下是否存在 Cookie 信息
- 存在 Cookie → 自動(dòng)將 Cookie 信息也發(fā)送給服務(wù)端,服務(wù)端會(huì)從 Cookie 中獲取 SessionID,再根據(jù) SessionID 查找對(duì)應(yīng)的 Session 信息
- 找到 Session → 證明用戶已經(jīng)登錄可執(zhí)行后面操作
- 未找到 Session → 可能是已過(guò)期的 Session 或者是假 Cookie
- 不存在 Cookie → 說(shuō)明用戶沒(méi)有登錄或者登錄失效
- 存在 Cookie → 自動(dòng)將 Cookie 信息也發(fā)送給服務(wù)端,服務(wù)端會(huì)從 Cookie 中獲取 SessionID,再根據(jù) SessionID 查找對(duì)應(yīng)的 Session 信息
原理說(shuō)明
- 登錄:客戶端提交登錄表單
- 校驗(yàn):服務(wù)器進(jìn)行登錄校驗(yàn)(如果校驗(yàn)失敗在直接拋出異常)
- 獲取 Session 對(duì)象
- Request 中已經(jīng)有 Session → 獲取 HttpSession 對(duì)象
- Request 中還沒(méi)有 Session → 創(chuàng)建 HttpSession 對(duì)象,并生成唯一標(biāo)識(shí)符(SessionId)
- request.getSession() // 如果 request 中有 session 則獲取
- 更新登錄狀態(tài):將用戶對(duì)象 user 以 USER_LOGIN_STATE 為鍵存儲(chǔ)在該 HttpSession 中
- USER_LOGIN_STATE 是一個(gè)常量,用來(lái)標(biāo)識(shí)用戶登錄狀態(tài)
- request.getSession().setAttribute(USER_LOGIN_STATE, user); // 更新Session登錄狀態(tài)
- 設(shè)置過(guò)期時(shí)間:設(shè)置該 HttpSession 的過(guò)期時(shí)間為 1 小時(shí)(即 1 小時(shí)如果內(nèi)沒(méi)有與該 HttpSession 關(guān)聯(lián)的請(qǐng)求,該 HttpSession 將被自動(dòng)銷毀)
request.getSession().setMaxInactiveInterval(60 * 60); // 設(shè)定Session過(guò)期時(shí)間
- 回傳 SessionId:服務(wù)器將 SessionId 寫入 Response Headers 中的 Set-Cookie
HTTP/1.1 200 OK Set-Cookie: JSESSIONID=1234567890ABCDEF; Path=/; HttpOnly
- 保存 SessionId:客戶端將 SessionId 存儲(chǔ)在 Cookie 中
- 客戶端請(qǐng)求資源:客戶端登錄后,每次訪問(wèn)服務(wù)器都會(huì)將 SessionId 寫在 請(qǐng)求頭的 Cookie 屬性中
GET /some/resource HTTP/1.1 Host: www.example.com Cookie: JSESSIONID=1234567890ABCDEF
四、示例
實(shí)現(xiàn)邏輯
創(chuàng)建 DTO 類- 創(chuàng)建 com.projectname.dto.UserDTO 類
- 定義 UserDTO 類中的屬性 (希望展示的 User 的屬性)
創(chuàng)建 UserHolder 工具類- 創(chuàng)建 com.projectname.utils.UserHolder 類
- 定義 ThreadLocal 本地線程 tl
- 定義 save / get / remove 方法
修改 UserServiceImpl 中的返回值- 調(diào)用 hutools 的 BeanUtil 工具類,使用其 copyProperties(User, UserDTO.class) 方法進(jìn)行 DTO 映射
- 修改 session 中的返回值 (User → UserDTO)
- session.setAttribute(”User”, BeanUtil.copyProperties( user, UserDTO.class)
修改 UserController 中的返回值- UserDTO user = UserHolder.getUser();
- 創(chuàng)建攔截器
- 獲取用戶請(qǐng)求的 Token 或其他標(biāo)識(shí)
- 驗(yàn)證 Token,并解析出用戶信息
- 將用戶信息存入
UserHolder - 在請(qǐng)求完成后清除
UserHolder的數(shù)據(jù),防止內(nèi)存泄漏
- 配置攔截器:注冊(cè)攔截器,讓其攔截需要驗(yàn)證的路徑
示例代碼
UserDTO 類(com.projectname.dto.UserDTO)
// com.projectname.dto.UserDTO
@Data
public class UserDTO {
private Long id;
private String nickName;
private String icon;
}
UserHolder 類(com.myproject.utils.UserHolder.java)
// com.projectname.utils.UserHolder
public class UserHolder {
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
public static void saveUser(UserDTO user){
tl.set(user);
}
public static UserDTO getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}- 攔截器(com.myproject.config.UserInterceptor.java)
- 目標(biāo):自動(dòng)攔截所有請(qǐng)求,如果有用戶信息則存入 UserHolder 中
@Component
public class UserInterceptor implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 從請(qǐng)求頭中獲取 Token,如果沒(méi)有 Token 則跳過(guò)攔截器(可能是未登錄狀態(tài))
String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token)) {
return true;
}
// 2. 校驗(yàn) Token 并解析用戶信息(此處簡(jiǎn)單模擬,實(shí)際應(yīng)調(diào)用 Token 驗(yàn)證服務(wù)或工具類)
UserDTO user = validateTokenAndGetUser(token);
if (user == null) { // 如果解析失敗,允許繼續(xù)(未登錄狀態(tài))
return true;
}
// 3. 將用戶信息保存到 UserHolder 中
UserHolder.setUser(user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 請(qǐng)求處理完成后清理 ThreadLocal,防止內(nèi)存泄漏
UserHolder.clear();
}
// 模擬 Token 校驗(yàn)并獲取用戶信息
private UserDTO validateTokenAndGetUser(String token) {
// 示例:模擬解析 Token 獲取用戶
if ("valid-token".equals(token)) {
return getUserByToken(token);
}
return null; // Token 無(wú)效或解析失敗
}}
- 配置攔截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor) // 注冊(cè)攔截器
.addPathPatterns("/**") // 攔截所有路徑
.excludePathPatterns("/login", "/register"); // 排除登錄、注冊(cè)等公開路徑
}
}到此這篇關(guān)于SpringBoot Cookie & Session 用戶登錄及登錄狀態(tài)保持功能實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)springboot cookie session用戶登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java數(shù)據(jù)結(jié)構(gòu)排序算法之歸并排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)排序算法之歸并排序,結(jié)合具體實(shí)例形式詳細(xì)分析了歸并排序的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05
mac下idea的svn密碼記不住的問(wèn)題及處理方法
這篇文章主要介紹了mac下idea的svn密碼記不住的問(wèn)題及處理方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
什么是springMVC?視圖和視圖解析器實(shí)例代碼
在 springMVC 中的目標(biāo)方法最終返回都是一個(gè)視圖,返回的視圖都會(huì)由一個(gè)視圖解析器來(lái)處理,這篇文章主要介紹了什么是springMVC?視圖和視圖解析器,需要的朋友可以參考下2023-09-09
Java線程的并發(fā)工具類實(shí)現(xiàn)原理解析
本文給大家講解Java線程的并發(fā)工具類的一些知識(shí),通過(guò)適用場(chǎng)景分析大數(shù)據(jù)量統(tǒng)計(jì)類任務(wù)的實(shí)現(xiàn)原理和封裝,多個(gè)示例代碼講解的非常詳細(xì),對(duì)java線程并發(fā)工具類相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)下吧2021-06-06
Mybatis-plus如何在xml中傳入自定義的SQL語(yǔ)句
這篇文章主要介紹了Mybatis-plus如何在xml中傳入自定義的SQL語(yǔ)句問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
java7鉆石語(yǔ)法知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是關(guān)于java7鉆石語(yǔ)法的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們參考下。2019-11-11
Java中的synchronized關(guān)鍵字全解析
synchronized是Java中用于解決并發(fā)問(wèn)題的核心關(guān)鍵字,通過(guò)確保多個(gè)線程對(duì)共享資源的互斥訪問(wèn),來(lái)避免線程安全問(wèn)題,synchronized具有原子性、可見(jiàn)性、有序性和可重入性等特性,本文給大家介紹Java中的synchronized關(guān)鍵字相關(guān),感興趣的朋友跟隨小編一起看看吧2026-01-01
Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái))
這篇文章主要介紹了Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

