個人博客:無奈何楊(wnhyang)
個人語雀:wnhyang
共享語雀:在線知識共享
Github:wnhyang - Overview文章來源:http://www.zghlxwxcb.cn/news/detail-808912.html
前文講了Sa-Token介紹與SpringBoot環(huán)境下使用,但是satoken
最重要的登錄鑒權(quán)直接略過了,那這篇文章就開講,??當(dāng)然不是啦??礃?biāo)題就知道這次要講的是satoken
組件,為什么這么安排呢,是因為我在細(xì)致了解satoken
源碼后,還是非常想把satoken
講的比較清楚細(xì)致的,包含其中一些設(shè)計模式的使用、函數(shù)式接口的應(yīng)用、組件注冊的方法等,而要講好這些,satoken
的組件一定要講一下吧,廢話不多說了,下面開始。
必要聲明:文章基于Sa-Token,版本1.37.0
satoken項目結(jié)構(gòu)
下載源碼
git clone https://github.com/dromara/Sa-Token.git
項目結(jié)構(gòu)介紹
項目結(jié)構(gòu)組織如下,結(jié)構(gòu)還是相當(dāng)清晰明了的。我也不可能把所有工程代碼詳細(xì)都講一下,只能根據(jù)satoken
最重要的模塊挑一部分細(xì)致講一下。
satoken核心
簡單介紹一下satoken
的項目結(jié)構(gòu),就可以步入本篇文章的正題了——satoken
組件。
sa-token-core
的組織結(jié)構(gòu)如下,包的命名已經(jīng)能說明一些什么了,接下來到了哪塊就細(xì)致來說哪塊。
SaManager
全類名路徑:cn.dev33.satoken.SaManager
以上結(jié)構(gòu)中最突出的就是SaManager
了,官方給他的定義如下,可見其重要性。
/**
* 管理 Sa-Token 所有全局組件,可通過此類快速獲取、寫入各種全局組件對象
*
* @author click33
* @since 1.18.0
*/
public class SaManager {
...
}
SaManager
的結(jié)構(gòu)如下,其中這些屬性就是satoken
最重要的組件了,下面挑出幾個細(xì)講一下。
SaTokenConfig
全類名路徑:cn.dev33.satoken.config.SaTokenConfig
config
包下除了SaTokenConfig
還有SaSignConfig
、SaCookieConfig
、SaTokenConfigFactory
。前三個屬于配置類,最后一個Factory
是用于非IOC
環(huán)境下使用的類。
satoken
的配置參考這一節(jié)就好Sa-Token,當(dāng)然這里完全和源碼相對應(yīng)的。
如前文所配置的,都對應(yīng)著類屬性。
############## Sa-Token 配置 (文檔: https://sa-token.cc) ##############
sa-token:
# token 名稱(同時也是 cookie 名稱)
token-name: Authorization
# token 有效期(單位:秒) 默認(rèn)30天,-1 代表永久有效
timeout: 3600
# token 最低活躍頻率(單位:秒),如果 token 超過此時間沒有訪問系統(tǒng)就會被凍結(jié),默認(rèn)-1 代表不限制,永不凍結(jié)
active-timeout: 1800
# 是否允許同一賬號多地同時登錄 (為 true 時允許一起登錄, 為 false 時新登錄擠掉舊登錄)
is-concurrent: false
# 在多人登錄同一賬號時,是否共用一個 token (為 true 時所有登錄共用一個 token, 為 false 時每次登錄新建一個 token)
is-share: true
# 是否嘗試從header里讀取token
is-read-header: true
# 是否嘗試從cookie里讀取token
is-read-cookie: false
# token前綴
token-prefix: "Bearer"
# token 風(fēng)格(默認(rèn)可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: tik
# 是否輸出操作日志
is-log: true
SaTokenConfig
部分截圖如下。
SaTokenDao
全類名路徑:cn.dev33.satoken.dao.SaTokenDao
Sa-Token,官方給他的描述是:SaTokenDao
是數(shù)據(jù)持久層接口,負(fù)責(zé)所有會話數(shù)據(jù)的底層寫入和讀取。
正如次,此接口設(shè)計了如下一些操作數(shù)據(jù)讀取與寫入的方法,注意其中包含抽象方法、默認(rèn)實現(xiàn)方法和默認(rèn)空實現(xiàn)方法。
與SaTokenDao
同dao
包下還有一個默認(rèn)實現(xiàn)類SaTokenDaoDefaultImpl
,當(dāng)然除此之外還有很多其他實現(xiàn)在插件工程里。
默認(rèn)實現(xiàn)SaTokenDaoDefaultImpl
:Sa-Token 持久層接口,默認(rèn)實現(xiàn)類(基于內(nèi)存 Map,系統(tǒng)重啟后數(shù)據(jù)丟失)。所以在不引入其他如Redis
需要注意重啟丟失的問題。
StpInterface
全類名路徑:cn.dev33.satoken.stp.StpInterface
前文講到自定義權(quán)限認(rèn)證時有講到,這個接口需要我們自己實現(xiàn)來滿足業(yè)務(wù)要求。
默認(rèn)實現(xiàn)類StpInterfaceDefaultImpl
也有說明。
/**
* 對 {@link StpInterface} 接口默認(rèn)的實現(xiàn)類
* <p>
* 如果開發(fā)者沒有實現(xiàn) StpInterface 接口,則框架會使用此默認(rèn)實現(xiàn)類,所有方法都返回空集合,即:用戶不具有任何權(quán)限和角色。
*
* @author click33
* @since 1.10.0
*/
public class StpInterfaceDefaultImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
return new ArrayList<>();
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
return new ArrayList<>();
}
}
同stp
包下還有很重要的StpUtil
、StpLogic
、SaTokenInfo
這次就先不講了。
SaTokenContext與SaTokenSecondContext
全類名路徑:cn.dev33.satoken.context.SaTokenContext/SaTokenSecondContext
Sa-Token,官方描述:上下文處理器封裝了當(dāng)前應(yīng)用環(huán)境的底層操作,是 Sa-Token 對接不同 web 框架的關(guān)鍵。目前 Sa-Token 僅對 SpringBoot、SpringMVC、WebFlux、Solon 等部分 Web 框架制作了 Starter 集成包, 如果我們使用的 Web 框架不在上述列表之中,則需要自定義 SaTokenContext 接口的實現(xiàn)完成整合工作。
core
工程context
包下的結(jié)構(gòu)是這樣的,其中SaHolder
是Sa-Token 上下文持有類,你可以通過此類快速獲取當(dāng)前環(huán)境下的 SaRequest、SaResponse、SaStorage、SaApplication 對象。關(guān)于satoken的三大作用域參考官網(wǎng)這篇文章Sa-Token。
對應(yīng)上官方所說對接不同web
框架,SaTokenContext
的實現(xiàn)有下,當(dāng)然對于我們使用最多的可能就是SaTokenContextForString
了。
SaLog
全類名路徑:cn.dev33.satoken.log.SaLog
Sa-Token 日志輸出接口,只有一個實現(xiàn)類就在同log
包下SaLogForConsole
。在看實現(xiàn)類的源碼時看到這個倒是漲一點知識??。挺有意思的。
/*
// 三種寫法速度對比
// if( config.getIsColorLog() != null && config.getIsColorLog() ) 10億次,2058ms
// if( config.getIsColorLog() == Boolean.TRUE ) 10億次,1050ms 最快
// if( Objects.equals(config.getIsColorLog(), Boolean.TRUE) ) 10億次,1543ms
*/
小結(jié)
關(guān)于SaManager
的組件就挑上面幾個介紹了一下。
剩下的SaTempInterface
(臨時 token
認(rèn)證模塊)、SaJsonTemplate
(JSON
轉(zhuǎn)換器)、SaSignTemplate
(API
參數(shù)簽名)、SaSameTemplate
(Same-Token
同源系統(tǒng)認(rèn)證模塊)就自己學(xué)習(xí)吧。
satoken組件注冊
簡單介紹了satoken
的組件,就要思考這些組件在項目中是如何使用的?如何管理的?
環(huán)境聲明
這里針對如下環(huán)境來講一下。
<!-- Sa-Token 權(quán)限認(rèn)證, 在線文檔:http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redisson-jackson</artifactId>
</dependency>
依賴關(guān)系
他們分別對應(yīng)有如下依賴。
sa-token-servlet
sa-token-servlet
僅僅是實現(xiàn)了前面context
章節(jié)的SaStorage
、SaRequest
、SaResponse
接口,并定義了一些錯誤碼。
sa-token-spring-boot-starter
sa-token-spring-boot-starter
也很簡單,關(guān)于SpringBoot
的自動裝配原理就不多講了,這里看resource/META-INF/spring.factories
文件,其實SpringBoot2.7
之后就換了,下面會提到。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.dev33.satoken.spring.SaTokenContextRegister
這里表示自動注入的是SaTokenContextRegister
。
1、注入了SaTokenContextForSpring
前面也有提到,其就是在SpringMVC環(huán)境下的上下文處理器,針對處理sa-token-servlet
實現(xiàn)的context
;
2、注入了SaPathCheckFilterForServlet
路徑檢查過濾器,自己可查看其代碼,這里略過。
/**
* 注冊 Sa-Token 框架所需要的 Bean
*
* @author click33
* @since 1.34.0
*/
public class SaTokenContextRegister {
/**
* 獲取上下文處理器組件 (Spring版)
*
* @return /
*/
@Bean
public SaTokenContext getSaTokenContextForSpring() {
return new SaTokenContextForSpring();
}
/**
* 請求 path 校驗過濾器
*
* @return /
*/
@Bean
public SaPathCheckFilterForServlet saPathCheckFilterForServlet() {
return new SaPathCheckFilterForServlet();
}
}
sa-token-redisson-jackson
好了,sa-token-spring-boot-starter
解決了確定context
的問題。
sa-token-redisson-jackson
要解決SaTokenDao
持久層實現(xiàn)的問題。前面提到SaTokenDao
有很多實現(xiàn),默認(rèn)實現(xiàn)在內(nèi)存中存儲數(shù)據(jù),這里使用了redisson
。
可以看到resource/META-INF/
不僅有spring.factories
還有spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
,這就是SpringBoot2.7
前后自動裝配的差別,有機(jī)會可以再探討一下。
resource/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
內(nèi)容如下
cn.dev33.satoken.dao.SaTokenDaoRedissonJackson
這里注入的是SaTokenDaoRedissonJackson
,是SaTokenDao
的一個實現(xiàn)類,具體方法實現(xiàn)自己學(xué)習(xí)吧??。其中SaSessionForJacksonCustomized
是SaSession
的Jackson
序列化實現(xiàn)類。
sa-token-spring-boot-autoconfig
重頭戲來了?。?!
前面那么多東西都要在這里串起來了。
直接開始!
resource/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
內(nèi)容如下
cn.dev33.satoken.spring.SaBeanRegister
cn.dev33.satoken.spring.SaBeanInject
cn.dev33.satoken.spring.sso.SaSsoBeanRegister
cn.dev33.satoken.spring.sso.SaSsoBeanInject
cn.dev33.satoken.spring.oauth2.SaOAuth2BeanRegister
cn.dev33.satoken.spring.oauth2.SaOAuth2BeanInject
這次先不看SSO
和OAuth2
的組件。只看SaBeanRegister
和SaBeanInject
最基礎(chǔ)的部分。
SaBeanRegister
/**
* 注冊Sa-Token所需要的Bean
* <p> Bean 的注冊與注入應(yīng)該分開在兩個文件中,否則在某些場景下會造成循環(huán)依賴
* @author click33
*
*/
public class SaBeanRegister {
/**
* 獲取配置Bean
*
* @return 配置對象
*/
@Bean
@ConfigurationProperties(prefix = "sa-token")
public SaTokenConfig getSaTokenConfig() {
return new SaTokenConfig();
}
/**
* 獲取 json 轉(zhuǎn)換器 Bean (Jackson版)
*
* @return json 轉(zhuǎn)換器 Bean (Jackson版)
*/
@Bean
public SaJsonTemplate getSaJsonTemplateForJackson() {
return new SaJsonTemplateForJackson();
}
/**
* 應(yīng)用上下文路徑加載器
* @return /
*/
@Bean
public ApplicationContextPathLoading getApplicationContextPathLoading() {
return new ApplicationContextPathLoading();
}
}
1、通過spring
配置文件前綴為sa-token
讀取SaTokenConfig
屬性注入
2和3略過。哈哈哈哈哈
SaBeanInject
觀察SaBeanInject
的結(jié)構(gòu),注意到其只有一個構(gòu)造器,剩下的都是空返回的set
方法而這些方法入?yún)⒍寂c前面的SaManager
里的組件幾乎完全對應(yīng)。
首先看這個構(gòu)造器,通過調(diào)用SaManager
的靜態(tài)方法來設(shè)置的。
/**
* 組件注入
* <p> 為確保 Log 組件正常打印,必須將 SaLog 和 SaTokenConfig 率先初始化 </p>
*
* @param log log 對象
* @param saTokenConfig 配置對象
*/
public SaBeanInject(
@Autowired(required = false) SaLog log,
@Autowired(required = false) SaTokenConfig saTokenConfig
){
if(log != null) {
SaManager.setLog(log);
}
if(saTokenConfig != null) {
SaManager.setConfig(saTokenConfig);
}
}
不知道你還記得前面有貼官方給SaManager
的定義:管理 Sa-Token 所有全局組件,可通過此類快速獲取、寫入各種全局組件對象。
回過頭來看SaManager
的屬性是怎么定義的,public volatile static SaTokenConfig config;
保證了多線程環(huán)境下的可見性和有序性。也就是SaTokenConfig
被更新后,其他線程能立刻看到變量更新。另外在getConfig
方法也使用了同步塊確保線程安全地獲取config
對象。
/**
* 全局配置對象
*/
public volatile static SaTokenConfig config;
public static void setConfig(SaTokenConfig config) {
setConfigMethod(config);
// 打印 banner
if(config !=null && config.getIsPrint()) {
SaFoxUtil.printSaToken();
}
// 如果此 config 對象沒有配置 isColorLog 的值,則框架為它自動判斷一下
if(config != null && config.getIsLog() != null && config.getIsLog() && config.getIsColorLog() == null) {
config.setIsColorLog(SaFoxUtil.isCanColorLog());
}
// $$ 全局事件
SaTokenEventCenter.doSetConfig(config);
// 調(diào)用一次 StpUtil 中的方法,保證其可以盡早的初始化 StpLogic
StpUtil.getLoginType();
}
private static void setConfigMethod(SaTokenConfig config) {
SaManager.config = config;
}
/**
* 獲取 Sa-Token 的全局配置信息
* @return 全局配置信息
*/
public static SaTokenConfig getConfig() {
if (config == null) {
synchronized (SaManager.class) {
if (config == null) {
setConfigMethod(SaTokenConfigFactory.createConfig());
}
}
}
return config;
}
SaBeanInject
的其他方法也沒有什么特別的,自己看就行了。
可以說SaBeanInject
是幫助SaManager
設(shè)置屬性的重要類,是之后直接使用StpUtil
、StpLogic
等靜態(tài)類的靜態(tài)方法的基礎(chǔ)。
寫在最后
拙作艱辛,字句心血,望諸君垂青,多予支持,不勝感激。
個人博客:無奈何楊(wnhyang)
個人語雀:wnhyang
共享語雀:在線知識共享
Github:wnhyang - Overview
文章來源地址http://www.zghlxwxcb.cn/news/detail-808912.html
到了這里,關(guān)于Sa-Token組件介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!