Sa-Token 是一個(gè)輕量級(jí) java 權(quán)限認(rèn)證框架愤兵,主要解決登錄認(rèn)證、權(quán)限認(rèn)證排吴、單點(diǎn)登錄秆乳、OAuth2、微服務(wù)網(wǎng)關(guān)鑒權(quán) 等一系列權(quán)限相關(guān)問(wèn)題钻哩。
Gitee 開(kāi)源地址:https://gitee.com/dromara/sa-token
本文將詳細(xì)介紹 Sa-Token 中的不同 SaSession 對(duì)象的區(qū)別屹堰,以及各種方便的存取值的方法。
一街氢、Session 是什么扯键?
Session 是會(huì)話中專(zhuān)業(yè)的數(shù)據(jù)緩存組件,通過(guò) Session 我們可以很方便的緩存一些高頻讀寫(xiě)數(shù)據(jù)珊肃,提高程序性能荣刑,例如:
// 在登錄時(shí)緩存user對(duì)象
StpUtil.getSession().set("user", user);
// 然后我們就可以在任意處使用這個(gè)user對(duì)象
SysUser user = (SysUser) StpUtil.getSession().get("user");
在 Sa-Token 中馅笙,SaSession 分為三種,分別是:
-
User-Session
: 指的是框架為每個(gè) 賬號(hào)id 分配的 SaSession厉亏。 -
Token-Session
: 指的是框架為每個(gè) token 分配的 SaSession董习。 -
Custom-Session
: 指的是以一個(gè) 特定的值 作為SessionId,來(lái)分配的 Session爱只。
假設(shè)三個(gè)客戶(hù)端登錄同一賬號(hào)皿淋,且配置了不共享token,那么此時(shí)的Session模型是:
簡(jiǎn)而言之:
-
User-Session
以UserId為主恬试,只要token指向的UserId一致窝趣,那么對(duì)應(yīng)的Session對(duì)象就一致。 -
Token-Session
以token為主忘渔,只要token不同高帖,那么對(duì)應(yīng)的Session對(duì)象就不同缰儿。 -
Custom-Session
以特定的key為主畦粮,不同key對(duì)應(yīng)不同的Session對(duì)象,同樣的key指向同一個(gè)Session對(duì)象乖阵。
二宣赔、獲取 User-Session
有關(guān)賬號(hào)Session的API如下:
// 獲取當(dāng)前賬號(hào)id的Session (必須是登錄后才能調(diào)用)
StpUtil.getSession();
// 獲取當(dāng)前賬號(hào)id的Session, 并決定在Session尚未創(chuàng)建時(shí),是否新建并返回
StpUtil.getSession(true);
// 獲取賬號(hào)id為10001的Session
StpUtil.getSessionByLoginId(10001);
// 獲取賬號(hào)id為10001的Session, 并決定在Session尚未創(chuàng)建時(shí)瞪浸,是否新建并返回
StpUtil.getSessionByLoginId(10001, true);
// 獲取SessionId為xxxx-xxxx的Session, 在Session尚未創(chuàng)建時(shí), 返回null
StpUtil.getSessionBySessionId("xxxx-xxxx");
三儒将、獲取 Token-Session
有關(guān)令牌Session的API如下:
// 獲取當(dāng)前 Token 的 Token-Session 對(duì)象
StpUtil.getTokenSession();
// 獲取指定 Token 的 Token-Session 對(duì)象
StpUtil.getTokenSessionByToken(token);
四、獲取自定義Session
自定義Session指的是以一個(gè)特定的值
作為SessionId來(lái)分配的Session
, 借助自定義Session对蒲,你可以為系統(tǒng)中的任意元素分配相應(yīng)的session
例如以商品id作為key為每個(gè)商品分配一個(gè)Session钩蚊,以便于緩存和商品相關(guān)的數(shù)據(jù),其相關(guān)API如下:
// 查詢(xún)指定key的Session是否存在
SaSessionCustomUtil.isExists("goods-10001");
// 獲取指定key的Session蹈矮,如果沒(méi)有砰逻,則新建并返回
SaSessionCustomUtil.getSessionById("goods-10001");
// 獲取指定key的Session,如果沒(méi)有泛鸟,第二個(gè)參數(shù)決定是否新建并返回
SaSessionCustomUtil.getSessionById("goods-10001", false);
// 刪除指定key的Session
SaSessionCustomUtil.deleteSessionById("goods-10001");
五蝠咆、在 Session 上存取值
// 寫(xiě)值
session.set("name", "zhang");
// 寫(xiě)值 (只有在此key原本無(wú)值的時(shí)候才會(huì)寫(xiě)入)
session.setDefaultValue("name", "zhang");
// 取值
session.get("name");
// 取值 (指定默認(rèn)值)
session.get("name", "<defaultValue>");
// 取值 (若無(wú)值則執(zhí)行參數(shù)方法, 之后將結(jié)果保存到此鍵名下,并返回此結(jié)果 若有值則直接返回, 無(wú)需執(zhí)行參數(shù)方法)
session.get("name", () -> {
return ...;
});
// ---------- 數(shù)據(jù)類(lèi)型轉(zhuǎn)換: ----------
session.getInt("age"); // 取值 (轉(zhuǎn)int類(lèi)型)
session.getLong("age"); // 取值 (轉(zhuǎn)long類(lèi)型)
session.getString("name"); // 取值 (轉(zhuǎn)String類(lèi)型)
session.getDouble("result"); // 取值 (轉(zhuǎn)double類(lèi)型)
session.getFloat("result"); // 取值 (轉(zhuǎn)float類(lèi)型)
session.getModel("key", Student.class); // 取值 (指定轉(zhuǎn)換類(lèi)型)
session.getModel("key", Student.class, <defaultValue>); // 取值 (指定轉(zhuǎn)換類(lèi)型, 并指定值為Null時(shí)返回的默認(rèn)值)
// 是否含有某個(gè)key (返回true或false)
session.has("key");
// 刪值
session.delete('name');
// 清空所有值
session.clear();
// 獲取此 Session 的所有key (返回Set<String>)
session.keys();
六、其它操作
// 返回此 Session 的id
session.getId();
// 返回此 Session 的創(chuàng)建時(shí)間 (時(shí)間戳)
session.getCreateTime();
// 返回此 Session 會(huì)話上的底層數(shù)據(jù)對(duì)象(如果更新map里的值北滥,請(qǐng)調(diào)用session.update()方法避免產(chǎn)生臟數(shù)據(jù))
session.getDataMap();
// 將這個(gè) Session 從持久庫(kù)更新一下
session.update();
// 注銷(xiāo)此 Session 會(huì)話 (從持久庫(kù)刪除此Session)
session.logout();
七刚操、SaSession 環(huán)境隔離說(shuō)明
有同學(xué)經(jīng)常會(huì)把 SaSession
與 HttpSession
進(jìn)行混淆,例如:
@PostMapping("/resetPoints")
public void reset(HttpSession session) {
// 在 HttpSession 上寫(xiě)入一個(gè)值
session.setAttribute("name", 66);
// 在 SaSession 進(jìn)行取值
System.out.println(StpUtil.getSession().get("name")); // 輸出null
}
要點(diǎn):
-
SaSession
與HttpSession
沒(méi)有任何關(guān)系再芋,在HttpSession
上寫(xiě)入的值菊霜,在SaSession
中無(wú)法取出。 -
HttpSession
并未被框架接管济赎,在使用Sa-Token時(shí)占卧,請(qǐng)?jiān)谌魏吻闆r下均使用SaSession
遗菠,不要使用HttpSession
豆瘫。
八庄萎、未登錄場(chǎng)景下獲取 Token-Session
默認(rèn)場(chǎng)景下,只有登錄后才能通過(guò) StpUtil.getTokenSession()
獲取 Token-Session
廊佩。
如果想要在未登錄場(chǎng)景下獲取 Token-Session 叭喜,有兩種方法:
- 方法一:將全局配置項(xiàng)
tokenSessionCheckLogin
改為 false贺拣。 - 方法二:使用匿名 Token-Session
// 獲取當(dāng)前 Token 的匿名 Token-Session (可在未登錄情況下使用的 Token-Session)
StpUtil.getAnonTokenSession();
注意點(diǎn):如果前端沒(méi)有提交 Token ,或者提交的 Token 是一個(gè)無(wú)效 Token 的話捂蕴,框架將不會(huì)根據(jù)此 Token 創(chuàng)建 Token-Session
對(duì)象譬涡,
而是隨機(jī)一個(gè)新的 Token 值來(lái)創(chuàng)建 Token-Session
對(duì)象,此 Token 值可以通過(guò) StpUtil.getTokenValue()
獲取到啥辨。
參考資料
- Sa-Token 文檔:https://sa-token.cc
- Gitee 倉(cāng)庫(kù)地址:https://gitee.com/dromara/sa-token
- GitHub 倉(cāng)庫(kù)地址:https://github.com/dromara/sa-token