身份認證和權限鑒別,是大多數系統都需要實現的邏輯。從最簡單的小型網站的用戶登錄,到極為龐大復雜的企業級用戶權限控制,權限認證可以只是簡單的判斷查詢,也可以是多種權限模型和身份驗證方式的復雜混合。
對于 JAVA 生態而言,權限認證早已是老生常談,如 Shiro、Security 等的傳統框架已是必經之路。然而,有沒有更為簡潔、能寫更少代碼和配置、更為符合實際業務需求的框架呢?Sa-Token 或許是一個更好的選擇。
簡介
Sa-Token,是 click33 在 Github 上開源的輕量級 Java 權限認證框架,目前版本為 v1.15.2。
Sa-Token 框架,主要解決的是:登錄認證、權限認證、Session會話、單點登錄、OAuth2.0 等一系列權限相關問題。框架針對:踢人下線、自動續簽、前后臺分離、分布式會話等常見業務進行了適配,使開發者可以以一種極簡的方式實現系統的權限認證邏輯。
與其他 Java 權限認證框架相比,sa-token 具有以下優勢:
- 簡單 :可零配置啟動框架,真正的開箱即用,低成本上手
- 強大:目前已集成幾十項權限相關特性,涵蓋了大部分業務場景的解決方案
- 易用:如絲般順滑的 API 調用,大量高級特性統統只需一行代碼即可實現
- 高擴展:幾乎所有組件都提供了擴展接口,90% 以上的邏輯都可以按需重寫
使用
要在項目中使用 Sa-Token,可以通過 Maven 引入,在 pom.xml 中加入依賴:
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.15.0.RELEASE</version>
</dependency>
也可以通過 Gradle 引入:
implementation 'cn.dev33:sa-token-spring-boot-starter:1.15.0.RELEASE'
Sa-Token 功能強大,覆蓋全面,包括:
- 登錄驗證 —— 輕松登錄鑒權,并提供五種細分場景值
- 權限驗證 —— 適配RBAC權限模型,不同角色不同授權
- Session會話 —— 專業的數據緩存中心
- 踢人下線 —— 將違規用戶立刻清退下線
- 持久層擴展 —— 可集成redis、Memcached等專業緩存中間件,重啟數據不丟失
- 分布式會話 —— 提供jwt集成和共享數據中心兩種分布式會話方案
- 單點登錄 —— 一處登錄,處處通行
- 模擬他人賬號 —— 實時操作任意用戶狀態數據
- 臨時身份切換 —— 將會話身份臨時切換為其它賬號
- 無Cookie模式 —— App、小程序等前后臺分離場景
- 同端互斥登錄 —— 像QQ一樣手機電腦同時在線,但是兩個手機上互斥登錄
- 多賬號認證體系 —— 比如一個商城項目的user表和admin表分開鑒權
- 花式token生成 —— 內置六種token風格,還可自定義token生成策略
- 注解式鑒權 —— 優雅的將鑒權與業務代碼分離
- 路由攔截式鑒權 —— 根據路由攔截鑒權,可適配restful模式
- 自動續簽 —— 提供兩種token過期策略,靈活搭配使用,還可自動續簽
- 會話治理 —— 提供方便靈活的會話查詢接口
- 記住我模式 —— 適配[記住我]模式,重啟瀏覽器免驗證
- 密碼加密 —— 提供密碼加密模塊,可快速MD5、SHA1、SHA256、AES、RSA加密
- 組件自動注入 —— 零配置與Spring等框架集成
Sa-Token 接口簡潔,使用方便。如果我們想要實現登錄和注銷,sa-token 提供了以下方式:
// 標記當前會話登錄的賬號id
// 建議的參數類型:long | int | String, 不可以傳入復雜類型,如:User、Admin等等
StpUtil.setLoginId(Object loginId);
// 當前會話注銷登錄
StpUtil.logout();
// 獲取當前會話是否已經登錄,返回true=已登錄,false=未登錄
StpUtil.isLogin();
// 檢驗當前會話是否已經登錄, 如果未登錄,則拋出異常:`NotLoginException`
StpUtil.checkLogin()
Sa-Token 還提供了可擴展性極強的權限驗證實現。Sa-Token 把【獲取當前賬號權限碼集合】的操作以接口方式暴露,開發者只需實現 StpInterface 接口:
package com.pj.satoken;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import cn.dev33.satoken.stp.StpInterface;
/**
* 自定義權限驗證接口擴展
*/
@Component // 保證此類被SpringBoot掃描,完成sa-token的自定義權限驗證擴展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一個賬號所擁有的權限碼集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginKey) {
// 本list僅做模擬,實際項目中要根據具體業務邏輯來查詢權限
List<String> list = new ArrayList<String>();
list.add("101");
list.add("user-add");
list.add("user-delete");
list.add("user-update");
list.add("user-get");
list.add("article-get");
return list;
}
/**
* 返回一個賬號所擁有的角色標識集合 (權限與角色可分開校驗)
*/
@Override
public List<String> getRoleList(Object loginId, String loginKey) {
// 本list僅做模擬,實際項目中要根據具體業務邏輯來查詢角色
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}
然后,我們就可以用以下的 API 來實現鑒權了:
// 當前賬號是否含有指定權限, 返回true或false
StpUtil.hasPermission("user:update");
// 當前賬號是否含有指定權限, 如果驗證未通過,則拋出異常: NotPermissionException
StpUtil.checkPermission("user:update");
// 當前賬號是否含有指定權限 [指定多個,必須全部驗證通過]
StpUtil.checkPermissionAnd("user:update", "user:delete");
// 當前賬號是否含有指定權限 [指定多個,只要其一驗證通過即可]
StpUtil.checkPermissionOr("user:update", "user:delete");
除此之外,Sa-Token 還有很多“一行式”的代碼,可以通過高度抽象的 API 完成復雜的功能:
StpUtil.setLoginId(10001); // 標記當前會話登錄的賬號id
StpUtil.getLoginId(); // 獲取當前會話登錄的賬號id
StpUtil.isLogin(); // 獲取當前會話是否已經登錄, 返回true或false
StpUtil.logout(); // 當前會話注銷登錄
StpUtil.logoutByLoginId(10001); // 讓賬號為10001的會話注銷登錄(踢人下線)
StpUtil.hasRole("super-admin"); // 查詢當前賬號是否含有指定角色標識, 返回true或false
StpUtil.hasPermission("user:add"); // 查詢當前賬號是否含有指定權限, 返回true或false
StpUtil.getSession(); // 獲取當前賬號id的Session
StpUtil.getSessionByLoginId(10001); // 獲取賬號id為10001的Session
StpUtil.getTokenValueByLoginId(10001); // 獲取賬號id為10001的token令牌值
StpUtil.setLoginId(10001, "PC"); // 指定設備標識登錄
StpUtil.logoutByLoginId(10001, "PC"); // 指定設備標識進行強制注銷 (不同端不受影響)
StpUtil.switchTo(10044); // 將當前會話身份臨時切換為其它賬號
總結
Sa-Token 作為一個輕量級 Java 權限認證框架,接口簡潔,功能強大,簡單易用,可擴展性強,能夠適應多種業務場景,無需繁瑣的配置文件和和全局過濾器,就能實現復雜和身份認證和權限控制,十分值得嘗試使用。