SpringBoot使用Sa-Token實現(xiàn)賬號封禁、分類封禁、階梯封禁的示例代碼
一、需求分析
之前的章節(jié)中,我們學(xué)習(xí)了 踢人下線 和 強制注銷 功能,用于清退違規(guī)賬號。在部分場景下,我們還需要將其 賬號封禁,以防止其再次登錄。
Sa-Token 是一個輕量級 java 權(quán)限認(rèn)證框架,主要解決登錄認(rèn)證、權(quán)限認(rèn)證、單點登錄、OAuth2、微服務(wù)網(wǎng)關(guān)鑒權(quán) 等一系列權(quán)限相關(guān)問題。 Gitee 開源地址:gitee.com/dromara/sa-token
Sa-Token 提供的封禁操作有三種:
- 賬號封禁:封禁掉一個賬號的登錄能力,使其無法登錄。
- 分類封禁:封禁掉一個賬號的部分業(yè)務(wù)操作權(quán)限,不影響賬號的整體登錄等基礎(chǔ)功能。
- 階梯封禁:按照不同的違規(guī)程度,給與其不同的封禁力度。
本篇文章將介紹在 Sa-Token 中如何完成上述三種封禁操作。
首先在項目中引入 Sa-Token 依賴:
<!-- Sa-Token 權(quán)限認(rèn)證 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.34.0</version> </dependency>
注:如果你使用的是 SpringBoot 3.x
,只需要將 sa-token-spring-boot-starter
修改為 sa-token-spring-boot3-starter
即可。
二、賬號封禁
對指定賬號進(jìn)行封禁:
// 封禁指定賬號 StpUtil.disable(10001, 86400);
參數(shù)含義:
- 參數(shù)1:要封禁的賬號id。
- 參數(shù)2:封禁時間,單位:秒,此為 86400秒 = 1天(此值為 -1 時,代表永久封禁)。
注意點:對于正在登錄的賬號,將其封禁并不會使它立即掉線,如果我們需要它即刻下線,可采用先踢再封禁的策略,例如:
// 先踢下線 StpUtil.kickout(10001); // 再封禁賬號 StpUtil.disable(10001, 86400);
待到下次登錄時,我們先校驗一下這個賬號是否已被封禁:
// 校驗指定賬號是否已被封禁,如果被封禁則拋出異常 `DisableServiceException` StpUtil.checkDisable(10001); // 通過校驗后,再進(jìn)行登錄: StpUtil.login(10001);
舊版本在
StpUtil.login()
時會自動校驗賬號是否被封禁,v1.31.0 之后將 校驗封禁 和 登錄 兩個動作分離成兩個方法,不再自動校驗,請注意其中的邏輯更改。
此模塊所有方法:
// 封禁指定賬號 StpUtil.disable(10001, 86400); // 獲取指定賬號是否已被封禁 (true=已被封禁, false=未被封禁) StpUtil.isDisable(10001); // 校驗指定賬號是否已被封禁,如果被封禁則拋出異常 `DisableServiceException` StpUtil.checkDisable(10001); // 獲取指定賬號剩余封禁時間,單位:秒,如果該賬號未被封禁,則返回-2 StpUtil.getDisableTime(10001); // 解除封禁 StpUtil.untieDisable(10001);
三、分類封禁
有的時候,我們并不需要將整個賬號禁掉,而是只禁止其訪問部分服務(wù)。
假設(shè)我們在開發(fā)一個電商系統(tǒng),對于違規(guī)賬號的處罰,我們設(shè)定三種分類封禁:
- 1、封禁評價能力:賬號A 因為多次虛假好評,被限制訂單評價功能。
- 2、封禁下單能力:賬號B 因為多次薅羊毛,被限制下單功能。
- 3、封禁開店能力:賬號C 因為店鋪銷售假貨,被限制開店功能。
相比于封禁賬號的一刀切處罰,這里的關(guān)鍵點在于:每一項能力封禁的同時,都不會對其它能力造成影響。
也就是說我們需要一種只對部分服務(wù)進(jìn)行限制的能力,對應(yīng)到代碼層面,就是只禁止部分接口的調(diào)用。
// 封禁指定用戶評論能力,期限為 1天 StpUtil.disable(10001, "comment", 86400);
參數(shù)釋義:
- 參數(shù)1:要封禁的賬號id。
- 參數(shù)2:針對這個賬號,要封禁的服務(wù)標(biāo)識(可以是任意的自定義字符串)。
- 參數(shù)3:要封禁的時間,單位:秒,此為 86400秒 = 1天(此值為 -1 時,代表永久封禁)。
分類封禁模塊所有可用API:
/* * 以下示例中:"comment"=評論服務(wù)標(biāo)識、"place-order"=下單服務(wù)標(biāo)識、"open-shop"=開店服務(wù)標(biāo)識 */ // 封禁指定用戶評論能力,期限為 1天 StpUtil.disable(10001, "comment", 86400); // 在評論接口,校驗一下,會拋出異常:`DisableServiceException`,使用 e.getService() 可獲取業(yè)務(wù)標(biāo)識 `comment` StpUtil.checkDisable(10001, "comment"); // 在下單時,我們校驗一下 下單能力,并不會拋出異常,因為我們沒有限制其下單功能 StpUtil.checkDisable(10001, "place-order"); // 現(xiàn)在我們再將其下單能力封禁一下,期限為 7天 StpUtil.disable(10001, "place-order", 86400 * 7); // 然后在下單接口,我們添加上校驗代碼,此時用戶便會因為下單能力被封禁而無法下單(代碼拋出異常) StpUtil.checkDisable(10001, "place-order"); // 但是此時,用戶如果調(diào)用開店功能的話,還是可以通過,因為我們沒有限制其開店能力 (除非我們再調(diào)用了封禁開店的代碼) StpUtil.checkDisable(10001, "open-shop");
通過以上示例,你應(yīng)該大致可以理解 業(yè)務(wù)封禁 -> 業(yè)務(wù)校驗
的處理步驟。
有關(guān)分類封禁的所有方法:
// 封禁:指定賬號的指定服務(wù) StpUtil.disable(10001, "<業(yè)務(wù)標(biāo)識>", 86400); // 判斷:指定賬號的指定服務(wù) 是否已被封禁 (true=已被封禁, false=未被封禁) StpUtil.isDisable(10001, "<業(yè)務(wù)標(biāo)識>"); // 校驗:指定賬號的指定服務(wù) 是否已被封禁,如果被封禁則拋出異常 `DisableServiceException` StpUtil.checkDisable(10001, "<業(yè)務(wù)標(biāo)識>"); // 獲?。褐付ㄙ~號的指定服務(wù) 剩余封禁時間,單位:秒(-1=永久封禁,-2=未被封禁) StpUtil.getDisableTime(10001, "<業(yè)務(wù)標(biāo)識>"); // 解封:指定賬號的指定服務(wù) StpUtil.untieDisable(10001, "<業(yè)務(wù)標(biāo)識>");
四、階梯封禁
對于多次違規(guī)的用戶,我們常常采取階梯處罰的策略,這種 “階梯” 一般有兩種形式:
- 處罰時間階梯:首次違規(guī)封禁 1 天,第二次封禁 7 天,第三次封禁 30 天,依次順延……
- 處罰力度階梯:首次違規(guī)消息提醒、第二次禁言禁評論、第三次禁止賬號登錄,等等……
基于處罰時間的階梯,我們只需在封禁時 StpUtil.disable(10001, 86400)
傳入不同的封禁時間即可,下面我們著重探討一下基于處罰力度的階梯形式。
假設(shè)我們在開發(fā)一個論壇系統(tǒng),對于違規(guī)賬號的處罰,我們設(shè)定三種力度:
- 1、輕度違規(guī):封禁其發(fā)帖、評論能力,但允許其點贊、關(guān)注等操作。
- 2、中度違規(guī):封禁其發(fā)帖、評論、點贊、關(guān)注等一切與別人互動的能力,但允許其瀏覽帖子、瀏覽評論。
- 3、重度違規(guī):封禁其登錄功能,限制一切能力。
解決這種需求的關(guān)鍵在于,我們需要把不同處罰力度,量化成不同的處罰等級,比如上述的 輕度
、中度
、重度
3 個力度, 我們將其量化為一級封禁
、二級封禁
、三級封禁
3個等級,數(shù)字越大代表封禁力度越高。
然后我們就可以使用階梯封禁的API,進(jìn)行鑒權(quán)了:
// 階梯封禁,參數(shù):封禁賬號、封禁級別、封禁時間 StpUtil.disableLevel(10001, 3, 10000); // 獲?。褐付ㄙ~號封禁的級別 (如果此賬號未被封禁則返回 -2) StpUtil.getDisableLevel(10001); // 判斷:指定賬號是否已被封禁到指定級別,返回 true 或 false StpUtil.isDisableLevel(10001, 3); // 校驗:指定賬號是否已被封禁到指定級別,如果已達(dá)到此級別(例如已被3級封禁,這里校驗是否達(dá)到2級),則拋出異常 `DisableServiceException` StpUtil.checkDisableLevel(10001, 2);
注意點:DisableServiceException
異常代表當(dāng)前賬號未通過封禁校驗,可以:
- 通過
e.getLevel()
獲取這個賬號實際被封禁的等級。 - 通過
e.getLimitLevel()
獲取這個賬號在校驗時要求低于的等級。當(dāng)Level >= LimitLevel
時,框架就會拋出異常。
如果業(yè)務(wù)足夠復(fù)雜,我們還可能將 分類封禁 和 階梯封禁 組合使用:
// 分類階梯封禁,參數(shù):封禁賬號、封禁服務(wù)、封禁級別、封禁時間 StpUtil.disableLevel(10001, "comment", 3, 10000); // 獲取:指定賬號的指定服務(wù) 封禁的級別 (如果此賬號未被封禁則返回 -2) StpUtil.getDisableLevel(10001, "comment"); // 判斷:指定賬號的指定服務(wù) 是否已被封禁到指定級別,返回 true 或 false StpUtil.isDisableLevel(10001, "comment", 3); // 校驗:指定賬號的指定服務(wù) 是否已被封禁到指定級別(例如 comment服務(wù) 已被3級封禁,這里校驗是否達(dá)到2級),如果已達(dá)到此級別,則拋出異常 StpUtil.checkDisableLevel(10001, "comment", 2);
五、使用注解完成封禁校驗
首先我們需要注冊 Sa-Token 全局?jǐn)r截器:
@Configuration public class SaTokenConfigure implements WebMvcConfigurer { // 注冊 Sa-Token 攔截器,打開注解式鑒權(quán)功能 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } }
然后我們就可以使用以下注解校驗賬號是否封禁:
// 校驗當(dāng)前賬號是否被封禁,如果已被封禁會拋出異常,無法進(jìn)入方法 @SaCheckDisable @PostMapping("send") public SaResult send() { // ... return SaResult.ok(); } // 校驗當(dāng)前賬號是否被封禁 comment 服務(wù),如果已被封禁會拋出異常,無法進(jìn)入方法 @SaCheckDisable("comment") @PostMapping("send") public SaResult send() { // ... return SaResult.ok(); } // 校驗當(dāng)前賬號是否被封禁 comment、place-order、open-shop 等服務(wù),指定多個值,只要有一個已被封禁,就無法進(jìn)入方法 @SaCheckDisable({"comment", "place-order", "open-shop"}) @PostMapping("send") public SaResult send() { // ... return SaResult.ok(); } // 階梯封禁,校驗當(dāng)前賬號封禁等級是否達(dá)到5級,如果達(dá)到則拋出異常 @SaCheckDisable(level = 5) @PostMapping("send") public SaResult send() { // ... return SaResult.ok(); } // 分類封禁 + 階梯封禁 校驗:校驗當(dāng)前賬號的 comment 服務(wù),封禁等級是否達(dá)到5級,如果達(dá)到則拋出異常 @SaCheckDisable(value = "comment", level = 5) @PostMapping("send") public SaResult send() { // ... return SaResult.ok(); }
六、來個小示例,加深理解
package com.pj.cases.up; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; /** * Sa-Token 賬號封禁示例 * * @author kong * @since 2022-10-17 */ @RestController @RequestMapping("/disable/") public class DisableController { // 會話登錄接口 ---- http://localhost:8081/disable/login?userId=10001 @RequestMapping("login") public SaResult login(long userId) { // 1、先檢查此賬號是否已被封禁 StpUtil.checkDisable(userId); // 2、檢查通過后,再登錄 StpUtil.login(userId); return SaResult.ok("賬號登錄成功"); } // 會話注銷接口 ---- http://localhost:8081/disable/logout @RequestMapping("logout") public SaResult logout() { StpUtil.logout(); return SaResult.ok("賬號退出成功"); } // 封禁指定賬號 ---- http://localhost:8081/disable/disable?userId=10001 @RequestMapping("disable") public SaResult disable(long userId) { /* * 賬號封禁: * 參數(shù)1:要封禁的賬號id * 參數(shù)2:要封禁的時間,單位:秒,86400秒=1天 */ StpUtil.disable(userId, 86400); return SaResult.ok("賬號 " + userId + " 封禁成功"); } // 解封指定賬號 ---- http://localhost:8081/disable/untieDisable?userId=10001 @RequestMapping("untieDisable") public SaResult untieDisable(long userId) { StpUtil.untieDisable(userId); return SaResult.ok("賬號 " + userId + " 解封成功"); } }
測試步驟:
- 訪問登錄接口,可以正常登錄 ----
http://localhost:8081/disable/login?userId=10001
- 注銷登錄 ----
http://localhost:8081/disable/logout
- 禁用賬號 ----
http://localhost:8081/disable/disable?userId=10001
- 再次訪問登錄接口,登錄失敗 ----
http://localhost:8081/disable/login?userId=10001
- 解封賬號 ----
http://localhost:8081/disable/untieDisable?userId=10001
- 再次訪問登錄接口,登錄成功 ----
http://localhost:8081/disable/login?userId=10001
參考資料
- Sa-Token 文檔:sa-token.cc
- Gitee 倉庫地址:gitee.com/dromara/sa-token
- GitHub 倉庫地址:github.com/dromara/sa-…
到此這篇關(guān)于SpringBoot使用Sa-Token實現(xiàn)賬號封禁、分類封禁、階梯封禁的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot賬號封禁、分類封禁、階梯封禁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于IntelliJ IDEA 打包代碼報錯的問題
這篇文章主要介紹了關(guān)于IntelliJ IDEA 打包代碼報錯的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03IDEA2021.2永久激活碼最新超詳細(xì)(激活到2099)
這篇文章主要介紹了IDEA2021.2永久激活碼,是idea2021版最新激活方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09spring boot如何使用AOP統(tǒng)一處理web請求
這篇文章主要介紹了spring boot如何使用AOP統(tǒng)一處理web請求,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12SpringCloud實現(xiàn)Redis在各個微服務(wù)的Session共享問題
Redis是運行在內(nèi)存中,查取速度很快。本文重點給大家介紹SpringCloud實現(xiàn)Redis在各個微服務(wù)的Session共享,感興趣的朋友一起看看吧2018-08-08