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

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

令牌技術(shù)(token)
令牌 : 用戶身份的標(biāo)識,實(shí)際上就是一個(gè)字符串
Cookie
定義:瀏覽器訪問服務(wù)器后,服務(wù)器傳給瀏覽器的一段數(shù)據(jù),由瀏覽器保存,后續(xù)通信中瀏覽器也要將 Cookie 發(fā)送給服務(wù)器功能- 識別用戶身份 (uid)
- 存儲用戶偏好:讓瀏覽器記住這位訪客的特定信息
工作條件- 瀏覽器每次訪問該服務(wù)器,都必須帶上 Cookie
- 瀏覽器需要保存 Cookie,不得輕易刪除
- 不能跨域
工作流程- 客戶端提交一個(gè)HTTP請求給服務(wù)端
- 服務(wù)端 Set-Cookie,同時(shí)提交響應(yīng)內(nèi)容給客戶端
- 客戶端再次向服務(wù)器請求,并在請求頭中攜帶一個(gè)Cookie
有效期- Expire 值:Cookie 在生成時(shí)就會被指定一個(gè) Expire 值,這就是 Cookie 的生存周期
- 立即清除 Cookie:生存周期設(shè)置為 “0” 或負(fù)值,這樣在關(guān)閉瀏覽器時(shí),就馬上清除 Cookie,不會記錄用戶信息,更加安全
缺點(diǎn)- 數(shù)量限制:一個(gè)瀏覽器能創(chuàng)建的 Cookie 數(shù)量最多為 300 個(gè),并且每個(gè)不能超過 4KB,每個(gè) Web 站點(diǎn)能設(shè)置的 Cookie 總數(shù)不能超過 20 個(gè)
- 安全性低:存在跨站點(diǎn)腳本攻擊的可能,腳本指令可以讀取當(dāng)前站點(diǎn)的所有 Cookie 內(nèi)容,并且可以提交到指定服務(wù)器重現(xiàn)其功能
問:為什么需要 Cookie 答:web程序使用的HTTP協(xié)議是無狀態(tài)的協(xié)議,對于事務(wù)處理沒有記憶能力,如果后續(xù)處理需要前面的信息則必須重傳,導(dǎo)致每次連接傳送的數(shù)據(jù)量增大
Session
一、概述
定義- Session (會話控制),Session 對象存儲特定用戶會話所需的屬性及配置信息
- SessionID:客戶端第一次請求服務(wù)器時(shí),服務(wù)器為客戶端算出的一個(gè)值,存儲在 Cookie 中,用于定位用戶 Session 在服務(wù)器中的位置
- 與 Cookie 的區(qū)別:Cookie 可以通過偽造來實(shí)現(xiàn)登錄并進(jìn)行一些 HTTP 請求,從安全性上來講,Session 比 Cookie 安全性稍微高一些
功能:提高安全性有效期:一般為半小時(shí),可以根據(jù)需求設(shè)定缺點(diǎn):Session 是存儲在服務(wù)器當(dāng)中的,所以 Session 過多,會對服務(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 :用戶第一次請求服務(wù)器的時(shí)候,服務(wù)器根據(jù)用戶提交的相關(guān)信息,創(chuàng)建對應(yīng)的 Session
- 響應(yīng) Session ID:服務(wù)器響應(yīng)請求時(shí),將此 Session 的唯一標(biāo)識信息 SessionID 返回給瀏覽器
- 存入 Cookie:瀏覽器接收到服務(wù)器返回的 SessionID 信息后,將此信息存入到 Cookie 中,同時(shí) Cookie 記錄此 SessionID 屬于哪個(gè)域名
- 攜帶 Cookie:當(dāng)用戶第二次訪問服務(wù)器的時(shí)候,請求會自動判斷此域名下是否存在 Cookie 信息
- 存在 Cookie → 自動將 Cookie 信息也發(fā)送給服務(wù)端,服務(wù)端會從 Cookie 中獲取 SessionID,再根據(jù) SessionID 查找對應(yīng)的 Session 信息
- 找到 Session → 證明用戶已經(jīng)登錄可執(zhí)行后面操作
- 未找到 Session → 可能是已過期的 Session 或者是假 Cookie
- 不存在 Cookie → 說明用戶沒有登錄或者登錄失效
- 存在 Cookie → 自動將 Cookie 信息也發(fā)送給服務(wù)端,服務(wù)端會從 Cookie 中獲取 SessionID,再根據(jù) SessionID 查找對應(yīng)的 Session 信息
原理說明
- 登錄:客戶端提交登錄表單
- 校驗(yàn):服務(wù)器進(jìn)行登錄校驗(yàn)(如果校驗(yàn)失敗在直接拋出異常)
- 獲取 Session 對象
- Request 中已經(jīng)有 Session → 獲取 HttpSession 對象
- Request 中還沒有 Session → 創(chuàng)建 HttpSession 對象,并生成唯一標(biāo)識符(SessionId)
- request.getSession() // 如果 request 中有 session 則獲取
- 更新登錄狀態(tài):將用戶對象 user 以 USER_LOGIN_STATE 為鍵存儲在該 HttpSession 中
- USER_LOGIN_STATE 是一個(gè)常量,用來標(biāo)識用戶登錄狀態(tài)
- request.getSession().setAttribute(USER_LOGIN_STATE, user); // 更新Session登錄狀態(tài)
- 設(shè)置過期時(shí)間:設(shè)置該 HttpSession 的過期時(shí)間為 1 小時(shí)(即 1 小時(shí)如果內(nèi)沒有與該 HttpSession 關(guān)聯(lián)的請求,該 HttpSession 將被自動銷毀)
request.getSession().setMaxInactiveInterval(60 * 60); // 設(shè)定Session過期時(shí)間
- 回傳 SessionId:服務(wù)器將 SessionId 寫入 Response Headers 中的 Set-Cookie
HTTP/1.1 200 OK Set-Cookie: JSESSIONID=1234567890ABCDEF; Path=/; HttpOnly
- 保存 SessionId:客戶端將 SessionId 存儲在 Cookie 中
- 客戶端請求資源:客戶端登錄后,每次訪問服務(wù)器都會將 SessionId 寫在 請求頭的 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)建攔截器
- 獲取用戶請求的 Token 或其他標(biāo)識
- 驗(yàn)證 Token,并解析出用戶信息
- 將用戶信息存入
UserHolder - 在請求完成后清除
UserHolder的數(shù)據(jù),防止內(nèi)存泄漏
- 配置攔截器:注冊攔截器,讓其攔截需要驗(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):自動攔截所有請求,如果有用戶信息則存入 UserHolder 中
@Component
public class UserInterceptor implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 從請求頭中獲取 Token,如果沒有 Token 則跳過攔截器(可能是未登錄狀態(tài))
String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token)) {
return true;
}
// 2. 校驗(yàn) Token 并解析用戶信息(此處簡單模擬,實(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 {
// 請求處理完成后清理 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 無效或解析失敗
}}
- 配置攔截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor) // 注冊攔截器
.addPathPatterns("/**") // 攔截所有路徑
.excludePathPatterns("/login", "/register"); // 排除登錄、注冊等公開路徑
}
}到此這篇關(guān)于SpringBoot Cookie & Session 用戶登錄及登錄狀態(tài)保持功能實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)springboot cookie session用戶登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 垃圾回收機(jī)制詳解(動力節(jié)點(diǎn)Java學(xué)院整理)
在系統(tǒng)運(yùn)行過程中,會產(chǎn)生一些無用的對象,這些對象占據(jù)著一定的內(nèi)存,如果不對這些對象清理回收無用對象的內(nèi)存,可能會導(dǎo)致內(nèi)存的耗盡,所以垃圾回收機(jī)制回收的是內(nèi)存。下面通過本文給大家詳細(xì)介紹java垃圾回收機(jī)制,一起學(xué)習(xí)吧2017-02-02
詳解SpringBoot 使用Spring Initializr 快速構(gòu)建工程(官方推薦)
本篇文章主要介紹了SpringBoot 使用Spring Initializr 快速構(gòu)建工程(官方推薦),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10
Spring Data JPA踩坑記錄(@id @GeneratedValue)
這篇文章主要介紹了Spring Data JPA踩坑記錄(@id @GeneratedValue),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Java中Prime算法的原理與實(shí)現(xiàn)詳解
Prime算法是一種窮舉查找算法來從一個(gè)連通圖中構(gòu)造一棵最小生成樹。本文主要為大家介紹了Java中Prime算法的原理與實(shí)現(xiàn),感興趣的可以學(xué)習(xí)一下2022-07-07
IntelliJ IDEA 2017.1.4 x64配置步驟(介紹)
下面小編就為大家?guī)硪黄狪ntelliJ IDEA 2017.1.4 x64配置步驟(介紹)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Java將Object轉(zhuǎn)換為數(shù)組的代碼
這篇文章主要介紹了Java將Object轉(zhuǎn)換為數(shù)組的情況,今天在使用一個(gè)別人寫的工具類,這個(gè)工具類,主要是判空操作,包括集合、數(shù)組、Map等對象是否為空的操作,需要的朋友可以參考下2022-09-09

