需求場景
封禁賬號是一個比較常見的業務需求,尤其是在論壇、社群型別的專案中,當出現了違規使用者時我們需要將其賬號立即封禁。
常規的設計思路是:在設計使用者表
時增加一個狀態欄位,例如:status
,其值為1時代表賬號正常,其值為0時代表賬號已被封禁。
當我們需要封禁一個賬號時,只需要將其賬號的status
值修改為0即可,對方再次登入系統時,我們便可以檢測到status
值不為1禁止登入。
這種模式雖然思路簡單,但也有一個不小的問題,那就是: 如果對方一直線上不登出登入呢?
由於我們只在登入時檢測status
值,這也就代表:如果對方不主動登出賬號,他的會話還是會一直存在且有效。
那怎麼才可以做到在封禁賬號後立即生效?
你可能會想到使用攔截器,攔截使用者的所有請求檢測賬號狀態:status=0
時禁止訪問,status=1
時再對請求放行
此方式雖然解決了問題,但是如果每次請求都要進行資料庫查詢的話,資料庫表示你如此掃蕩我你就沒有一點心理壓力嗎?
那怎麼辦?上快取?雖然可以緩解效能壓力,但似乎總感覺沒有完美解決問題。
真正的問題點在於:一個正常的系統只有0.01%的使用者是需要封禁的,我們對其它99.99%使用者的實時檢測都是不必要的效能浪費。
在如上場景中,我們真正需要的是一個踢人下線的操作,即:我們需要在封禁某個使用者後,使他的會話立即掉線,即時他重新登入也會被禁止登入
那麼,怎麼做到實時踢人下線呢?
筆者使用的是sa-token
許可權認證框架,這個框架封裝了踢人下線操作呼叫非常方便,不用像其它框架一樣還需要我自己再封裝一層才能做到。
具體程式碼
- 首先新增
pom.xml
框架
<!-- sa-token 許可權認證, 線上文件:http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.12.1</version>
</dependency>
- 在使用者登入時將賬號id寫入會話中
@RestController
@RequestMapping("user")
public class UserController {
@RequestMapping("doLogin")
public String doLogin(String username, String password) {
// 此處僅作示例模擬,真實專案需要從資料庫中查詢資料進行比對
if("zhang".equals(username) && "123456".equals(password)) {
StpUtil.setLoginId(10001);
return "登入成功";
}
return "登入失敗";
}
}
- 將指定id的賬號
// 使指定id賬號的會話登出登入,對方再次訪問系統時會丟擲`NotLoginException`異常,場景值為-5
@RequestMapping("kickout")
public String kickout(long userId) {
StpUtil.logoutByLoginId(userId);
return "剔出成功";
}
關鍵程式碼就在 StpUtil.logoutByLoginId(userId)
這一句,使指定id的賬號登出登入 (踢人下線)
如果覺得文章寫得不錯還請大家不要吝惜為文章點個贊,您的支援是我更新的最大動力!
最後附上專案連結:
- 官網文件:http://sa-token.dev33.cn/
- Gitee開源地址: https://gitee.com/sz6/sa-token
- GitHub開源地址: https://github.com/click33/sa-token