springboot整合Sa-Token實(shí)現(xiàn)登錄認(rèn)證和權(quán)限校驗(yàn)的詳細(xì)流程
目前在國(guó)內(nèi)的后端開(kāi)發(fā)中,常用的安全框架有spring security、shiro。現(xiàn)在,介紹一款由國(guó)人開(kāi)發(fā)的安全框架Sa-Token。這個(gè)框架完全由國(guó)人開(kāi)發(fā),所提供的Api文檔和一些設(shè)置都是比較符合國(guó)人的開(kāi)發(fā)習(xí)慣的,本次就來(lái)介紹一下如何在spring boot框架中整合Sa-Token框架,以實(shí)現(xiàn)我們最常使用的登錄認(rèn)證和權(quán)限校驗(yàn);
Sa-Token的官網(wǎng)地址如下:
Sa-Token
Sa-Token 是由國(guó)人開(kāi)發(fā)的 一個(gè)輕量級(jí) Java 權(quán)限認(rèn)證框架,主要解決:登錄認(rèn)證、權(quán)限認(rèn)證、單點(diǎn)登錄、OAuth2.0、分布式Session會(huì)話、微服務(wù)網(wǎng)關(guān)鑒權(quán) 等一系列權(quán)限相關(guān)問(wèn)題。
版本:spring boot3.15、Sa-Token1.37.0
1、新建一個(gè)spring boot項(xiàng)目,并導(dǎo)入一些起始的依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
<!-- Sa-Token 權(quán)限認(rèn)證,在線文檔:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>2、新建五張數(shù)據(jù)表,來(lái)展示登錄認(rèn)證和權(quán)限校驗(yàn):
1、用戶表
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
2、角色表
CREATE TABLE roles ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE, description VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
3、權(quán)限表
CREATE TABLE permissions ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE, description VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
4、用戶角色表
CREATE TABLE user_roles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, role_id INT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (role_id) REFERENCES roles(id) );
5、角色權(quán)限表
CREATE TABLE role_permissions ( id INT AUTO_INCREMENT PRIMARY KEY, role_id INT NOT NULL, permission_id INT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (role_id) REFERENCES roles(id), FOREIGN KEY (permission_id) REFERENCES permissions(id) );
3、現(xiàn)在我們開(kāi)始進(jìn)行基于Sa-Token進(jìn)行的登錄校驗(yàn)和權(quán)限認(rèn)證:
與spring security不同的是,引入了Sa-Token的依賴之后。并不會(huì)自動(dòng)生效,需要我們自己編寫(xiě)相應(yīng)的邏輯代碼;
寫(xiě)一個(gè)TestController,用來(lái)進(jìn)行測(cè)試;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public String hello() {
System.out.println("說(shuō)hello啊");
return "test接口的hello";
}
}我們現(xiàn)在啟動(dòng)項(xiàng)目,并訪問(wèn)/test/hello接口,發(fā)現(xiàn)能夠正常訪問(wèn)。這一點(diǎn)與spring security是不同的,spring security默認(rèn)會(huì)攔截所有請(qǐng)求;
Sa-Token已經(jīng)為我們編寫(xiě)了很多我們經(jīng)常使用的功能,我們只需要在yml配置文件中進(jìn)行配置即可。以下是一些常用的配置:
############## Sa-Token 配置 (文檔: https://sa-token.cc) ##############
sa-token:
# token 名稱(同時(shí)也是 cookie 名稱)
token-name: satoken
# token 有效期(單位:秒) 默認(rèn)30天,-1 代表永久有效
timeout: 2592000
# token 最低活躍頻率(單位:秒),如果 token 超過(guò)此時(shí)間沒(méi)有訪問(wèn)系統(tǒng)就會(huì)被凍結(jié),默認(rèn)-1 代表不限制,永不凍結(jié)
active-timeout: -1
# 是否允許同一賬號(hào)多地同時(shí)登錄 (為 true 時(shí)允許一起登錄, 為 false 時(shí)新登錄擠掉舊登錄)
is-concurrent: true
# 在多人登錄同一賬號(hào)時(shí),是否共用一個(gè) token (為 true 時(shí)所有登錄共用一個(gè) token, 為 false 時(shí)每次登錄新建一個(gè) token)
is-share: true
# token 風(fēng)格(默認(rèn)可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: uuid
# 是否輸出操作日志
is-log: true3.1、登錄認(rèn)證:
使用Sa-Token進(jìn)行登錄認(rèn)證是非常簡(jiǎn)單的,只需要一句代碼就可以搞定:
// 會(huì)話登錄:參數(shù)填寫(xiě)要登錄的賬號(hào)id,建議的數(shù)據(jù)類(lèi)型:long | int | String, 不可以傳入復(fù)雜類(lèi)型,如:User、Admin 等等 StpUtil.login(Object id);
只此一句代碼,便可以使會(huì)話登錄成功,實(shí)際上,Sa-Token 在背后做了大量的工作,包括但不限于:
- 檢查此賬號(hào)是否之前已有登錄;
- 為賬號(hào)生成
Token憑證與Session會(huì)話; - 記錄 Token 活躍時(shí)間;
- 通知全局偵聽(tīng)器,xx 賬號(hào)登錄成功;
- 將
Token注入到請(qǐng)求上下文; - 等等其它工作……
我們暫時(shí)不需要完整了解整個(gè)登錄過(guò)程,只需要記住關(guān)鍵一點(diǎn):Sa-Token 為這個(gè)賬號(hào)創(chuàng)建了一個(gè)Token憑證,且通過(guò) Cookie 上下文返回給了前端。
一個(gè)登錄接口:
@Autowired
IUsersService usersService;
@PostMapping("/login")
public SaResult login(String username, String password){
//根據(jù)用戶名從數(shù)據(jù)庫(kù)中查詢
Users users = usersService.getOne(new LambdaQueryWrapper<Users>().eq(Users::getUsername, username));
if(users == null){
return SaResult.error("用戶名不存在");
}
if(!users.getPassword().equals(password)){
return SaResult.error("密碼錯(cuò)誤");
}
//根據(jù)用戶id登錄
StpUtil.login(users.getId());
return SaResult.ok("登錄成功");
}運(yùn)行檢驗(yàn):

發(fā)現(xiàn)確實(shí)能夠登錄成功。
此處僅僅做了會(huì)話登錄,但并沒(méi)有主動(dòng)向前端返回 token 信息。 是因?yàn)椴恍枰獑幔繃?yán)格來(lái)講是需要的,只不過(guò) StpUtil.login(id) 方法利用了 Cookie 自動(dòng)注入的特性,省略了你手寫(xiě)返回 token 的代碼。
如果你對(duì) Cookie 功能還不太了解,也不用擔(dān)心,我們會(huì)在之后的 [ 前后端分離 ] 章節(jié)中詳細(xì)的闡述 Cookie 功能,現(xiàn)在你只需要了解最基本的兩點(diǎn):
- Cookie 可以從后端控制往瀏覽器中寫(xiě)入 token 值。
- Cookie 會(huì)在前端每次發(fā)起請(qǐng)求時(shí)自動(dòng)提交 token 值。
因此,在 Cookie 功能的加持下,我們可以僅靠 StpUtil.login(id) 一句代碼就完成登錄認(rèn)證。
除了登錄方法,我們還需要:
// 當(dāng)前會(huì)話注銷(xiāo)登錄 StpUtil.logout(); // 獲取當(dāng)前會(huì)話是否已經(jīng)登錄,返回true=已登錄,false=未登錄 StpUtil.isLogin(); // 檢驗(yàn)當(dāng)前會(huì)話是否已經(jīng)登錄, 如果未登錄,則拋出異常:`NotLoginException` StpUtil.checkLogin();
異常 NotLoginException 代表當(dāng)前會(huì)話暫未登錄,可能的原因有很多: 前端沒(méi)有提交 token、前端提交的 token 是無(wú)效的、前端提交的 token 已經(jīng)過(guò)期 …… 等等
還有一些登錄過(guò)程中常用的方法:
// 獲取當(dāng)前會(huì)話賬號(hào)id, 如果未登錄,則拋出異常:`NotLoginException` StpUtil.getLoginId(); // 類(lèi)似查詢API還有: StpUtil.getLoginIdAsString(); // 獲取當(dāng)前會(huì)話賬號(hào)id, 并轉(zhuǎn)化為`String`類(lèi)型 StpUtil.getLoginIdAsInt(); // 獲取當(dāng)前會(huì)話賬號(hào)id, 并轉(zhuǎn)化為`int`類(lèi)型 StpUtil.getLoginIdAsLong(); // 獲取當(dāng)前會(huì)話賬號(hào)id, 并轉(zhuǎn)化為`long`類(lèi)型 // ---------- 指定未登錄情形下返回的默認(rèn)值 ---------- // 獲取當(dāng)前會(huì)話賬號(hào)id, 如果未登錄,則返回 null StpUtil.getLoginIdDefaultNull(); // 獲取當(dāng)前會(huì)話賬號(hào)id, 如果未登錄,則返回默認(rèn)值 (`defaultValue`可以為任意類(lèi)型) StpUtil.getLoginId(T defaultValue); // 獲取當(dāng)前會(huì)話的 token 值 StpUtil.getTokenValue(); // 獲取當(dāng)前`StpLogic`的 token 名稱 StpUtil.getTokenName(); // 獲取指定 token 對(duì)應(yīng)的賬號(hào)id,如果未登錄,則返回 null StpUtil.getLoginIdByToken(String tokenValue); // 獲取當(dāng)前會(huì)話剩余有效期(單位:s,返回-1代表永久有效) StpUtil.getTokenTimeout(); // 獲取當(dāng)前會(huì)話的 token 信息參數(shù) StpUtil.getTokenInfo();
3.1.1前后端分離模式下的登錄(無(wú)cookie模式)
無(wú) Cookie 模式:特指不支持 Cookie 功能的終端,通俗來(lái)講就是我們常說(shuō)的 —— 前后端分離模式。
常規(guī) Web 端鑒權(quán)方法,一般由 Cookie模式 完成,而 Cookie 有兩個(gè)特性:
- 可由后端控制寫(xiě)入。
- 每次請(qǐng)求自動(dòng)提交。
這就使得我們?cè)谇岸舜a中,無(wú)需任何特殊操作,就能完成鑒權(quán)的全部流程(因?yàn)檎麄€(gè)流程都是后端控制完成的)
而在app、小程序等前后端分離場(chǎng)景中,一般是沒(méi)有 Cookie 這一功能的,此時(shí)大多數(shù)人都會(huì)一臉懵逼,咋進(jìn)行鑒權(quán)???
見(jiàn)招拆招,其實(shí)答案很簡(jiǎn)單:
- 不能后端控制寫(xiě)入了,就前端自己寫(xiě)入。(后端將登錄成功之后生成的Token 傳遞到前端)
- 每次請(qǐng)求不能自動(dòng)提交了,那就手動(dòng)提交。(前端將登陸成功后獲取的Token封裝到請(qǐng)求頭中每次請(qǐng)求時(shí)都攜帶,后端將其讀取出來(lái),并判斷用戶信息)
修改我們之前寫(xiě)的登錄接口,返回token給前端;
@PostMapping("/login")
public SaResult login(String username, String password){
//根據(jù)用戶名從數(shù)據(jù)庫(kù)中查詢
Users users = usersService.getOne(new LambdaQueryWrapper<Users>().eq(Users::getUsername, username));
if(users == null){
return SaResult.error("用戶名不存在");
}
if(!users.getPassword().equals(password)){
return SaResult.error("密碼錯(cuò)誤");
}
//根據(jù)用戶id登錄,第1步,先登錄上
StpUtil.login(users.getId());
// 第2步,獲取 Token 相關(guān)參數(shù)
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
// 第3步,返回給前端
return SaResult.data(tokenInfo);
}在進(jìn)行一次登錄:

可以看到登錄成功之后,返回了很多相關(guān)的數(shù)據(jù),而我們的token也在其中,那么前端就可以將token取出來(lái)放到一個(gè)狀態(tài)管理器(pinia中),并且在每次請(qǐng)求時(shí)都將token放在請(qǐng)求頭中。
如果你對(duì) Cookie 非常了解,那你就會(huì)明白,所謂 Cookie ,本質(zhì)上就是一個(gè)特殊的header參數(shù)而已, 而既然它只是一個(gè) header 參數(shù),我們就能手動(dòng)模擬實(shí)現(xiàn)它,從而完成鑒權(quán)操作。
3.1.2路由攔截鑒權(quán):
假設(shè)我們有如下需求:
項(xiàng)目中所有接口均需要登錄認(rèn)證,只有 “登錄接口” 本身對(duì)外開(kāi)放
我們?cè)趺磳?shí)現(xiàn)呢?給每個(gè)接口加上鑒權(quán)注解?手寫(xiě)全局?jǐn)r截器?似乎都不是非常方便。
在這個(gè)需求中我們真正需要的是一種基于路由攔截的鑒權(quán)模式,那么在Sa-Token怎么實(shí)現(xiàn)路由攔截鑒權(quán)呢?
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注冊(cè)攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注冊(cè) Sa-Token 攔截器,校驗(yàn)規(guī)則為 StpUtil.checkLogin() 登錄校驗(yàn)。
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns("/users/login");
}
}以上代碼,我們注冊(cè)了一個(gè)基于 StpUtil.checkLogin() 的登錄校驗(yàn)攔截器,并且排除了/user/login接口用來(lái)開(kāi)放登錄(除了/user/login以外的所有接口都需要登錄才能訪問(wèn))這就與我們spring security有了一點(diǎn)點(diǎn)相似了,因?yàn)閟pring security默認(rèn)的就是所有的接口都被攔截到。
我們?cè)賳?dòng)項(xiàng)目,并訪問(wèn)我們最開(kāi)始寫(xiě)的/test/hello接口;

可以看到這個(gè)接口被攔截了。那么我們帶上之前登錄成功,生成的token之后再去訪問(wèn)呢?

可以看到我們成功訪問(wèn)了這個(gè)接口;
new SaInterceptor(handle -> StpUtil.checkLogin()) 是最簡(jiǎn)單的寫(xiě)法,代表只進(jìn)行登錄校驗(yàn)功能。實(shí)際上Sa-Token還可以實(shí)現(xiàn)一些更詳細(xì)的校驗(yàn)規(guī)則,在Sa-Token的官網(wǎng)上可以看到。
3.1.3持久化
Sa-Token 默認(rèn)將數(shù)據(jù)保存在內(nèi)存中,此模式讀寫(xiě)速度最快,且避免了序列化與反序列化帶來(lái)的性能消耗,但是此模式也有一些缺點(diǎn),比如:
- 重啟后數(shù)據(jù)會(huì)丟失。
- 無(wú)法在分布式環(huán)境中共享數(shù)據(jù)。
所以,sa-token為我們提供了持久化的方法,我們可以在登錄成功之后將token數(shù)據(jù)存儲(chǔ)到redis中。然后,每次請(qǐng)求時(shí)到redis中取到我們的token數(shù)據(jù)。這樣就實(shí)現(xiàn)了即使重啟服務(wù),我們之前的登錄token也不會(huì)丟失
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.37.0</version>
</dependency>sa-token已經(jīng)幫我們整合了redis,我們自需要引入相應(yīng)的pom依賴。其他的上層Api都不變。
3.2權(quán)限校驗(yàn):
我們已經(jīng)了解了常用的登錄認(rèn)證方法,接下來(lái),我們來(lái)看一下權(quán)限校驗(yàn);
1、獲取當(dāng)前用戶的權(quán)限碼集合:
因?yàn)槊總€(gè)項(xiàng)目的需求不同,其權(quán)限設(shè)計(jì)也千變?nèi)f化,因此 [ 獲取當(dāng)前賬號(hào)權(quán)限碼集合 ] 這一操作不可能內(nèi)置到框架中, 所以 Sa-Token 將此操作以接口的方式暴露給你,以方便你根據(jù)自己的業(yè)務(wù)邏輯進(jìn)行重寫(xiě)。
你需要做的就是新建一個(gè)類(lèi),實(shí)現(xiàn) StpInterface接口
/**
* 自定義權(quán)限加載接口實(shí)現(xiàn)類(lèi)
*/
@Component // 保證此類(lèi)被 SpringBoot 掃描,完成 Sa-Token 的自定義權(quán)限驗(yàn)證擴(kuò)展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一個(gè)賬號(hào)所擁有的權(quán)限碼集合
*/
// 角色權(quán)限表
@Autowired
IRolePermissionsService rolePermissionsService;
// 用戶角色表
@Autowired
IUserRolesService userRolesService;
//權(quán)限表
@Autowired
IPermissionsService permissionsService;
// 角色表
@Autowired
IRolesService rolesService;
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 根據(jù)用戶id從用戶角色表中獲取角色id
List<UserRoles> roleIds = userRolesService.list(new LambdaQueryWrapper<UserRoles>()
.eq(UserRoles::getUserId,Integer.parseInt(loginId.toString())));
List<Integer> rolesList = roleIds.stream().map(UserRoles::getRoleId).toList();
if (!(rolesList.size() >0)){
// 沒(méi)有任何權(quán)限
return null;
}
List<String> list = new ArrayList<>();
rolesList.forEach(roleId ->{
// 根據(jù)角色id從角色權(quán)限表中獲取權(quán)限id
List<RolePermissions> rolePermissions = rolePermissionsService.list(new LambdaQueryWrapper<RolePermissions>().
eq(RolePermissions::getRoleId, roleId));
// 根據(jù)權(quán)限id從權(quán)限表中獲取權(quán)限名稱
rolePermissions.forEach(permissionsId->{
Permissions permissions = permissionsService.getById(permissionsId.getPermissionId());
list.add(permissions.getName());
});
});
// 返回用戶所有權(quán)限,
return list;
}
/**
* 返回一個(gè)賬號(hào)所擁有的角色標(biāo)識(shí)集合 (權(quán)限與角色可分開(kāi)校驗(yàn))
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 本 list 僅做模擬,實(shí)際項(xiàng)目中要根據(jù)具體業(yè)務(wù)邏輯來(lái)查詢角色
// 根據(jù)用戶id從用戶角色表中獲取角色id
List<UserRoles> roleIds = userRolesService.list(new LambdaQueryWrapper<UserRoles>()
.eq(UserRoles::getUserId,Integer.parseInt(loginId.toString())));
List<String> list = new ArrayList<>();
if (!(roleIds.size() >0)){
// 用戶沒(méi)有分配角色
return null;
}
roleIds.forEach(roleId ->{
Roles byId = rolesService.getById(roleId.getRoleId());
list.add(byId.getName());
});
// 返回用戶所有角色標(biāo)識(shí)集合
return list;
}
}我所實(shí)現(xiàn)的是標(biāo)準(zhǔn)的RBAC(基于用戶、角色、權(quán)限的訪問(wèn)控制模型)。所以,在得到用戶id的情況下、先根據(jù)用戶角色表查出角色id、在根據(jù)角色權(quán)限表查詢權(quán)限id,在根據(jù)權(quán)限表查出具體權(quán)限名稱。
上面使用了Mybatis-plus的條件構(gòu)造器和stream流的形式進(jìn)行查詢。
參數(shù)解釋:
- loginId:賬號(hào)id,即你在調(diào)用
StpUtil.login(id)時(shí)寫(xiě)入的標(biāo)識(shí)值。 - loginType:賬號(hào)體系標(biāo)識(shí),此處可以暫時(shí)忽略,在 [ 多賬戶認(rèn)證 ] 章節(jié)下會(huì)對(duì)這個(gè)概念做詳細(xì)的解釋。
有同學(xué)會(huì)產(chǎn)生疑問(wèn):我實(shí)現(xiàn)了此接口,但是程序啟動(dòng)時(shí)好像并沒(méi)有執(zhí)行,是不是我寫(xiě)錯(cuò)了? 答:不執(zhí)行是正?,F(xiàn)象,程序啟動(dòng)時(shí)不會(huì)執(zhí)行這個(gè)接口的方法,在每次調(diào)用鑒權(quán)代碼時(shí),才會(huì)執(zhí)行到此。
權(quán)限校驗(yàn):
然后就可以用以下 api 來(lái)鑒權(quán)了:
// 獲?。寒?dāng)前賬號(hào)所擁有的權(quán)限集合
StpUtil.getPermissionList();
// 判斷:當(dāng)前賬號(hào)是否含有指定權(quán)限, 返回 true 或 false
StpUtil.hasPermission("user.add");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定權(quán)限, 如果驗(yàn)證未通過(guò),則拋出異常: NotPermissionException
StpUtil.checkPermission("user.add");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定權(quán)限 [指定多個(gè),必須全部驗(yàn)證通過(guò)]
StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定權(quán)限 [指定多個(gè),只要其一驗(yàn)證通過(guò)即可]
StpUtil.checkPermissionOr("user.add", "user.delete", "user.get"); 擴(kuò)展:NotPermissionException 對(duì)象可通過(guò) getLoginType() 方法獲取具體是哪個(gè) StpLogic 拋出的異常
角色校驗(yàn):
在 Sa-Token 中,角色和權(quán)限可以分開(kāi)獨(dú)立驗(yàn)證
// 獲?。寒?dāng)前賬號(hào)所擁有的角色集合
StpUtil.getRoleList();
// 判斷:當(dāng)前賬號(hào)是否擁有指定角色, 返回 true 或 false
StpUtil.hasRole("super-admin");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定角色標(biāo)識(shí), 如果驗(yàn)證未通過(guò),則拋出異常: NotRoleException
StpUtil.checkRole("super-admin");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定角色標(biāo)識(shí) [指定多個(gè),必須全部驗(yàn)證通過(guò)]
StpUtil.checkRoleAnd("super-admin", "shop-admin");
// 校驗(yàn):當(dāng)前賬號(hào)是否含有指定角色標(biāo)識(shí) [指定多個(gè),只要其一驗(yàn)證通過(guò)即可]
StpUtil.checkRoleOr("super-admin", "shop-admin"); 擴(kuò)展:NotRoleException 對(duì)象可通過(guò) getLoginType() 方法獲取具體是哪個(gè) StpLogic 拋出的異常
權(quán)限通配符:
Sa-Token允許你根據(jù)通配符指定泛權(quán)限,例如當(dāng)一個(gè)賬號(hào)擁有art.*的權(quán)限時(shí),art.add、art.delete、art.update都將匹配通過(guò)
// 當(dāng)擁有 art.* 權(quán)限時(shí)
StpUtil.hasPermission("art.add"); // true
StpUtil.hasPermission("art.update"); // true
StpUtil.hasPermission("goods.add"); // false
// 當(dāng)擁有 *.delete 權(quán)限時(shí)
StpUtil.hasPermission("art.delete"); // true
StpUtil.hasPermission("user.delete"); // true
StpUtil.hasPermission("user.update"); // false
// 當(dāng)擁有 *.js 權(quán)限時(shí)
StpUtil.hasPermission("index.js"); // true
StpUtil.hasPermission("index.css"); // false
StpUtil.hasPermission("index.html"); // false上帝權(quán)限:當(dāng)一個(gè)賬號(hào)擁有 "*" 權(quán)限時(shí),他可以驗(yàn)證通過(guò)任何權(quán)限碼 (角色認(rèn)證同理)
在我們的項(xiàng)目的TestController中進(jìn)行測(cè)試:
@GetMapping("/hello")
public String hello() {
System.out.println("驗(yàn)證權(quán)限,是否具有‘所有權(quán)限'===============>"+StpUtil.hasPermission("所有權(quán)限"));
System.out.println("驗(yàn)證角色,是否具有‘管理員'角色===============>"+StpUtil.hasRole("管理員"));
System.out.println("說(shuō)hello啊");
return "test接口的hello";
}我們測(cè)試的最終結(jié)果:

可以看到確實(shí)輸出了兩個(gè)true。并且,只有在每次調(diào)用鑒權(quán)代碼時(shí),才會(huì)執(zhí)行到我們自定義的權(quán)限方法中。
總結(jié):
我本來(lái)是想寫(xiě)一篇介紹spring boot項(xiàng)目中整合Sa-Token來(lái)實(shí)現(xiàn)最常用的登錄校驗(yàn)和權(quán)限認(rèn)證的,但是寫(xiě)著寫(xiě)著就變成官網(wǎng)的復(fù)制機(jī)了。我在本篇文章中大量復(fù)制了官網(wǎng)上的內(nèi)容,原本只是想復(fù)制一些官方介紹就行了。但是這也從側(cè)面說(shuō)明了Sa-Token官網(wǎng)制作的確實(shí)是比較好的,基本上不需要額外的學(xué)習(xí),只要你有做過(guò)登錄和權(quán)限方面的項(xiàng)目經(jīng)驗(yàn),再看一遍官網(wǎng)的介紹就能直接上手了。
我之前寫(xiě)過(guò)一個(gè)B2C模式的購(gòu)物商臺(tái),分為用戶端和管理端。管理端的登錄和權(quán)限校驗(yàn)是用spring security寫(xiě)的?,F(xiàn)在又了解了Sa-Token之后,真的還是認(rèn)為Sa-Token的使用是比較簡(jiǎn)單的。(也可能是我的項(xiàng)目還是比較簡(jiǎn)單的,并沒(méi)有多少權(quán)限要實(shí)現(xiàn))并且這也是我們國(guó)人寫(xiě)的開(kāi)源框架,在一些方法的封裝、Api的設(shè)計(jì)上還是能直接理解的。在這里也算是為Sa-Token這個(gè)框架打個(gè)廣告吧,希望大家還是能夠多多支持國(guó)產(chǎn),國(guó)內(nèi)的開(kāi)源之路也是充滿了坎坷與艱辛。
到此這篇關(guān)于springboot整合Sa-Token實(shí)現(xiàn)登錄認(rèn)證和權(quán)限校驗(yàn)的詳細(xì)流程的文章就介紹到這了,更多相關(guān)springboot Sa-Token登錄認(rèn)證和權(quán)限校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合Sa-Token實(shí)現(xiàn)RBAC權(quán)限模型的過(guò)程解析
- springboot整合sa-token中的redis報(bào)netty錯(cuò)誤問(wèn)題
- springboot?整合?SA-Token?使用詳解
- sa-token整合springboot中的代碼示例展示
- SpringBoot整合Sa-Token實(shí)現(xiàn)?API?接口簽名安全校驗(yàn)功能
- springboot 整合 sa-token簡(jiǎn)介及入門(mén)教程
- Springboot 如何使用 SaToken 進(jìn)行登錄認(rèn)證、權(quán)限管理及路由規(guī)則接口攔截
- SpringBoot中給指定接口加上權(quán)限校驗(yàn)的實(shí)現(xiàn)
- SpringBoot切面實(shí)現(xiàn)token權(quán)限校驗(yàn)詳解
相關(guān)文章
Mybatis調(diào)用存儲(chǔ)過(guò)程的案例
這篇文章主要介紹了Mybatis如何調(diào)用存儲(chǔ)過(guò)程,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
SpringBoot+Redis實(shí)現(xiàn)不重復(fù)消費(fèi)的隊(duì)列的示例代碼
本文主要介紹了SpringBoot+Redis實(shí)現(xiàn)不重復(fù)消費(fèi)的隊(duì)列的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
Spring詳細(xì)講解事務(wù)失效的場(chǎng)景
實(shí)際項(xiàng)目開(kāi)發(fā)中,如果涉及到多張表操作時(shí),為了保證業(yè)務(wù)數(shù)據(jù)的一致性,大家一般都會(huì)采用事務(wù)機(jī)制,好多小伙伴可能只是簡(jiǎn)單了解一下,遇到事務(wù)失效的情況,便會(huì)無(wú)從下手,下面這篇文章主要給大家介紹了關(guān)于Spring事務(wù)失效場(chǎng)景的相關(guān)資料,需要的朋友可以參考下2022-07-07
Springboot整合Swagger3全注解配置(springdoc-openapi-ui)
本文主要介紹了Springboot整合Swagger3全注解配置(springdoc-openapi-ui),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Java基礎(chǔ)之ArrayList的擴(kuò)容機(jī)制
這篇文章主要介紹了Java基礎(chǔ)之ArrayList的擴(kuò)容機(jī)制,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
SpringBoot定時(shí)任務(wù)的實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringBoot定時(shí)任務(wù)的實(shí)現(xiàn)詳解,定時(shí)任務(wù)是企業(yè)級(jí)開(kāi)發(fā)中最常見(jiàn)的功能之一,如定時(shí)統(tǒng)計(jì)訂單數(shù)、數(shù)據(jù)庫(kù)備份、定時(shí)發(fā)送短信和郵件、定時(shí)統(tǒng)計(jì)博客訪客等,簡(jiǎn)單的定時(shí)任務(wù)可以直接通過(guò)Spring中的@Scheduled注解來(lái)實(shí)現(xiàn),需要的朋友可以參考下2024-01-01
Java中Map與對(duì)象之間互相轉(zhuǎn)換的幾種常用方式
在Java中將對(duì)象和Map相互轉(zhuǎn)換是常見(jiàn)的操作,可以通過(guò)不同的方式實(shí)現(xiàn)這種轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于Java中Map與對(duì)象之間互相轉(zhuǎn)換的幾種常用方式,需要的朋友可以參考下2024-01-01
詳解SpringBoot的jar為什么可以直接運(yùn)行
SpringBoot提供了一個(gè)插件spring-boot-maven-plugin用于把程序打包成一個(gè)可執(zhí)行的jar包,本文給大家介紹了為什么SpringBoot的jar可以直接運(yùn)行,文中有相關(guān)的代碼示例供大家參考,感興趣的朋友可以參考下2024-02-02

