需求場景
說起登錄,你可能會不屑一顧,還有比這更簡單的功能嗎?
獲取一下用戶提交參數(shù) username + password 和數(shù)據(jù)庫中一比對,有記錄返回[登錄成功],無記錄返回[用戶名或密碼錯(cuò)誤]
什么,就這?
當(dāng)你熟練的打包、部署、啟動項(xiàng)目開始了一天的摸魚之后,產(chǎn)品經(jīng)理開始坐不住了
“小順子啊,你看咱們的APP登錄能不能加一個(gè)功能,就是那種......那個(gè)......一個(gè)用戶登錄之后,能把上一個(gè)登錄的自動擠下線”
此時(shí)的你陷入了沉思,怎么讓他在登錄之后,把上一個(gè)登錄者的會話給擠下線呢?
難道說要在每次登錄之后循環(huán)一遍Session列表,找到與此用戶同賬號的會話將其注銷,聰明如你馬上想到了這種方案將會給服務(wù)器帶來巨大的性能壓力!
那怎么辦?難道要建個(gè)Map以userId做key、Session做value,建立起映射關(guān)系,然后手動取出Session做上標(biāo)記[已被擠下線]?
說干就干,當(dāng)你擼起袖子,噼里啪啦敲好上述邏輯之后,然后測試、打包、部署、上傳一氣呵成,又開始了一天的摸魚......
然而你還是低估了產(chǎn)品經(jīng)理的腦洞能力
“小順子,你看你寫的功能有點(diǎn)小問題啊,我每次一登錄,就會把其它登錄地給擠掉線啊?!?/p>
此時(shí)的你下意識反駁到: "有什么問題?這難道不就是你想要的效果嗎?"
“en....就是....咱們能不能這樣,我在手機(jī)上登錄,能不能只把別的手機(jī)上給擠下線,但是我電腦上已經(jīng)登錄的不受影響”
“擠掉肯定是全部擠掉啊,怎么可能只留下你電腦端不擠掉呢?你要的功能不可能做到”
只見此時(shí)產(chǎn)品經(jīng)理嘴角輕輕一笑,放出了大招:
“那人家騰訊QQ是怎么做到的呢?”
一句話暴擊99999+,頓時(shí)你啞口無言,是呀,騰訊QQ怎么做到這種功能的呢?一個(gè)QQ號可以在手機(jī)和電腦上同時(shí)在線,但是卻不能兩個(gè)手機(jī)同時(shí)在線
難道說在登錄時(shí)再記錄時(shí)每次登錄的設(shè)備標(biāo)識?循環(huán)檢測登錄列表的設(shè)備名稱,同設(shè)備擠下線,不同設(shè)備保持登錄?
產(chǎn)品經(jīng)理沖上咖啡,帶著勝利的微笑離開了房間,只留下一臉愁容的你,冥思苦想著實(shí)現(xiàn)方案……
正題
好了,說了這么多,下面進(jìn)入今天的主題————sa-token,一個(gè)可以讓你輕松解決各種登錄問題的權(quán)限認(rèn)證框架!
如上述場景所言,你遇到的問題不過是三個(gè)典型的登錄模型:多地登錄、單地登錄、同端互斥登錄
- 多地登錄:指同一賬號可以在任意地點(diǎn)同時(shí)登錄,互不影響
- 單地登錄:在同一時(shí)間一個(gè)賬號只能在一個(gè)地點(diǎn)登錄,新登錄會擠掉舊登錄者
- 同端互斥登錄:在同一類型設(shè)備上只允許單地點(diǎn)登錄,在不同類型設(shè)備上允許同時(shí)在線
接下來讓我們看看使用sa-token是如何輕松處理這三種登錄問題的
多地登錄
此模式較為簡單,sa-token默認(rèn)模式即為多地登錄模式
- 首先添加
pom.xml框架
<!-- sa-token 權(quán)限認(rèn)證, 在線文檔:http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.12.1</version>
</dependency>
- 在用戶登錄時(shí)將賬號id寫入會話中
@RestController
@RequestMapping("user")
public class UserController {
@RequestMapping("doLogin")
public String doLogin(String username, String password) {
// 此處僅作示例模擬,真實(shí)項(xiàng)目需要從數(shù)據(jù)庫中查詢數(shù)據(jù)進(jìn)行比對
if("zhang".equals(username) && "123456".equals(password)) {
StpUtil.setLoginId(10001);
return "登錄成功";
}
return "登錄失敗";
}
}
- 新建啟動類啟動
@SpringBootApplication
public class SaTokenDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenDemoApplication.class, args);
System.out.println("\n啟動成功:sa-token配置如下:" + SaTokenManager.getConfig());
}
}
至此,我們已經(jīng)完成了多地點(diǎn)登錄的全部代碼,上述代碼在多人登錄同一賬號時(shí)將不會對舊會話做任何處理,同一賬號可以在多個(gè)地點(diǎn)任意登錄,互不影響
單地登錄
單地登錄與多地登錄唯一的差異就是, 需要改一下yml配置文件
spring:
# sa-token配置
sa-token:
allow-concurrent-login: false
配置項(xiàng) allow-concurrent-login 的含義為:是否允許同一賬號并發(fā)登錄 (此值為true時(shí)允許一起登錄, 為false時(shí)新登錄擠掉舊登錄)
其它代碼與[多地登錄]無異,當(dāng)我們在兩個(gè)瀏覽器分別登錄同一賬號時(shí),舊會話再次訪問系統(tǒng)將會得到如下提示:
{
"code": 401,
"msg": "token已被頂下線",
"data": null,
"dataCount": null
}
同端互斥登錄
好了,終于到了最終難題,同端互斥登錄可以讓我們像騰訊QQ一樣,在同一類型設(shè)備上只允許單地點(diǎn)登錄,在不同類型設(shè)備上允許同時(shí)在線
那么在sa-token中如何做到同端互斥登錄呢?
首先如單地登錄一樣,在配置文件中,將 allowConcurrentLogin 配置為false,然后調(diào)用登錄等相關(guān)接口時(shí)聲明設(shè)備標(biāo)識即可:
指定設(shè)備標(biāo)識登錄
StpUtil.setLoginId(10001, "PC");
調(diào)用此方法登錄后,同設(shè)備的會被頂下線(不同設(shè)備不受影響),再次訪問系統(tǒng)時(shí)會拋出 NotLoginException 異常,場景值=-4
指定設(shè)備標(biāo)識強(qiáng)制注銷(踢人下線)
StpUtil.logoutByLoginId(10001, "PC");
如果第二個(gè)參數(shù)填寫null或不填,代表將這個(gè)賬號id所有在線端踢下線,被踢出者再次訪問系統(tǒng)時(shí)會拋出 NotLoginException 異常,場景值=-5
查詢當(dāng)前登錄的設(shè)備標(biāo)識
StpUtil.getLoginDevice();
結(jié)尾
以上就是sa-token框架在處理登錄問題時(shí)的各種技巧,可以看出不管是簡單的多地登錄還是復(fù)雜的同端互斥登錄,在sa-token都有完成的解決方案
sa-token是近期開源的國產(chǎn)優(yōu)秀權(quán)限認(rèn)證框架,除了各種登錄認(rèn)證,sa-token還可以輕松解決項(xiàng)目中的各種權(quán)限認(rèn)證問題,
比如:踢人下線、自動續(xù)簽、身份臨時(shí)切換等常見業(yè)務(wù)均可以一行代碼調(diào)用實(shí)現(xiàn),接下來的文章我會逐一介紹這些特性,讓大家對sa-token有一個(gè)全面的了解
如果覺得文章寫得不錯(cuò)還請大家不要吝惜為文章點(diǎn)個(gè)贊,您的支持是我更新的最大動力!
最后附上項(xiàng)目鏈接:
- 官網(wǎng)文檔:http://sa-token.dev33.cn/
- Gitee開源地址: https://gitee.com/sz6/sa-token
- GitHub開源地址: https://github.com/click33/sa-token