所謂權限認證,核心邏輯就是判斷帳號是否擁有指定權限:
有,就讓你通過。
沒有?那麼禁止訪問!
深入到底層資料中,就是每個帳號都會擁有一個權限碼集合,框架來校驗這個集合中是否包含指定的權限碼。
例如:目前帳號擁有權限碼集合["user-add", "user-delete", "user-get"]
,這時候我來校驗權限 "user-update"
,則其結果就是:驗證失敗,禁止存取。
所以現在問題的核心就是:
如何取得帳號所擁有的權限碼集合?
本次操作需要驗證的權限碼是哪一個?
接下來,我們將介紹在 SpringBoot 中如何使用 Sa-Token 完成權限認證操作。
Sa-Token 是一個輕量級 java 權限認證框架,主要解決登入認證、權限認證、單一登入、OAuth3、微服務閘道鑑權 等一系列權限相關問題。
首先在專案中引入Sa-Token 依賴:
<!-- Sa-Token 权限认证 --> <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
即可。
因為每個項目的需求不同,其權限設計也千變萬化,因此[ 取得目前帳號權限碼集合] 這項運算不可能內建到框架中,所以Sa-Token 將此操作以介面的方式暴露給你,以方便你根據自己的業務邏輯進行重寫。
你需要做的就是新建一個類,實作StpInterface
接口,例如以下程式碼:
/** * 自定义权限验证接口扩展 */ @Component // 保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展 public class StpInterfaceImpl implements StpInterface { /** * 返回一个账号所拥有的权限码集合 */ @Override public List<String> getPermissionList(Object loginId, String loginType) { // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限 List<String> list = new ArrayList<String>(); list.add("101"); list.add("user.add"); list.add("user.update"); list.add("user.get"); // list.add("user.delete"); list.add("art.*"); return list; } /** * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验) */ @Override public List<String> getRoleList(Object loginId, String loginType) { // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色 List<String> list = new ArrayList<String>(); list.add("admin"); list.add("super-admin"); return list; } }
參數解釋:
StpUtil.login(id) 時寫入的識別值。
注意點:類別上一定要加上@Component 註解,保證元件被Springboot 掃描到,成功注入到Sa-Token框架內。
@SpringBootApplication public class SaTokenCaseApplication { public static void main(String[] args) { SpringApplication.run(SaTokenCaseApplication.class, args); System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig()); } }
// 获取:当前账号所拥有的权限集合 StpUtil.getPermissionList(); // 判断:当前账号是否含有指定权限, 返回 true 或 false StpUtil.hasPermission("user.add"); // 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException StpUtil.checkPermission("user.add"); // 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过] StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get"); // 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] StpUtil.checkPermissionOr("user.add", "user.delete", "user.get");
NotPermissionException 物件可透過
getLoginType() 方法取得具體是哪個
StpLogic 拋出的例外
// 获取:当前账号所拥有的角色集合 StpUtil.getRoleList(); // 判断:当前账号是否拥有指定角色, 返回 true 或 false StpUtil.hasRole("super-admin"); // 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException StpUtil.checkRole("super-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] StpUtil.checkRoleAnd("super-admin", "shop-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] StpUtil.checkRoleOr("super-admin", "shop-admin");
NotRoleException 物件可透過
getLoginType() 方法取得具體是哪個
StpLogic拋出的異常
當然不行!
你可以建立一個全域例外攔截器,統一回傳給前端的格式,參考:@RestControllerAdvice public class GlobalExceptionHandler { // 全局异常拦截 @ExceptionHandler public SaResult handlerException(Exception e) { e.printStackTrace(); return SaResult.error(e.getMessage()); } }
泛權限,例如當帳號擁有art.*的權限時,
art.add、
art.delete、
art.update都會匹配通過
// 当拥有 art.* 权限时 StpUtil.hasPermission("art.add"); // true StpUtil.hasPermission("art.update"); // true StpUtil.hasPermission("goods.add"); // false // 当拥有 *.delete 权限时 StpUtil.hasPermission("art.delete"); // true StpUtil.hasPermission("user.delete"); // true StpUtil.hasPermission("user.update"); // false // 当拥有 *.js 权限时 StpUtil.hasPermission("index.js"); // true StpUtil.hasPermission("index.css"); // false StpUtil.hasPermission("index.html"); // false
上帝權限:當帳號擁有七、如何把權限精確到按鈕級? 權限精確到按鈕層級的意思是指:"*"
權限時,他可以驗證通過任何權限碼(角色認證同理)
權限範圍可以控製到頁面上的每個按鈕是否顯示。
思路:如此精確的範圍控制只依賴後端已經難以完成,此時需要前端進行一定的邏輯判斷。 如果是前後端一體項目,可以參考:Thymeleaf 標籤方言,如果是前後端分離項目,則:localStorage或其它全域狀態管理物件中。
Vue框架中我們可以使用以下寫入:
<button v-if="arr.indexOf('user.delete') > -1">删除按钮</button>
arr是目前使用者擁有的權限碼數組,
user.delete是顯示按鈕需要擁有的權限碼,
刪除按鈕是使用者擁有權限碼才可以看到的內容。
需要!
前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!
新建 JurAuthController
,复制以下代码
package com.pj.cases.use; import java.util.List; 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-13 */ @RestController @RequestMapping("/jur/") public class JurAuthController { /* * 前提1:首先调用登录接口进行登录,代码在 com.pj.cases.use.LoginAuthController 中有详细解释,此处不再赘述 * ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456 * * 前提2:项目实现 StpInterface 接口,代码在 com.pj.satoken.StpInterfaceImpl * Sa-Token 将从此实现类获取 每个账号拥有哪些权限。 * * 然后我们就可以使用以下示例中的代码进行鉴权了 */ // 查询权限 ---- http://localhost:8081/jur/getPermission @RequestMapping("getPermission") public SaResult getPermission() { // 查询权限信息 ,如果当前会话未登录,会返回一个空集合 List<String> permissionList = StpUtil.getPermissionList(); System.out.println("当前登录账号拥有的所有权限:" + permissionList); // 查询角色信息 ,如果当前会话未登录,会返回一个空集合 List<String> roleList = StpUtil.getRoleList(); System.out.println("当前登录账号拥有的所有角色:" + roleList); // 返回给前端 return SaResult.ok() .set("roleList", roleList) .set("permissionList", permissionList); } // 权限校验 ---- http://localhost:8081/jur/checkPermission @RequestMapping("checkPermission") public SaResult checkPermission() { // 判断:当前账号是否拥有一个权限,返回 true 或 false // 如果当前账号未登录,则永远返回 false StpUtil.hasPermission("user.add"); StpUtil.hasPermissionAnd("user.add", "user.delete", "user.get"); // 指定多个,必须全部拥有才会返回 true StpUtil.hasPermissionOr("user.add", "user.delete", "user.get"); // 指定多个,只要拥有一个就会返回 true // 校验:当前账号是否拥有一个权限,校验不通过时会抛出 `NotPermissionException` 异常 // 如果当前账号未登录,则永远校验失败 StpUtil.checkPermission("user.add"); StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get"); // 指定多个,必须全部拥有才会校验通过 StpUtil.checkPermissionOr("user.add", "user.delete", "user.get"); // 指定多个,只要拥有一个就会校验通过 return SaResult.ok(); } // 角色校验 ---- http://localhost:8081/jur/checkRole @RequestMapping("checkRole") public SaResult checkRole() { // 判断:当前账号是否拥有一个角色,返回 true 或 false // 如果当前账号未登录,则永远返回 false StpUtil.hasRole("admin"); StpUtil.hasRoleAnd("admin", "ceo", "cfo"); // 指定多个,必须全部拥有才会返回 true StpUtil.hasRoleOr("admin", "ceo", "cfo"); // 指定多个,只要拥有一个就会返回 true // 校验:当前账号是否拥有一个角色,校验不通过时会抛出 `NotRoleException` 异常 // 如果当前账号未登录,则永远校验失败 StpUtil.checkRole("admin"); StpUtil.checkRoleAnd("admin", "ceo", "cfo"); // 指定多个,必须全部拥有才会校验通过 StpUtil.checkRoleOr("admin", "ceo", "cfo"); // 指定多个,只要拥有一个就会校验通过 return SaResult.ok(); } // 权限通配符 ---- http://localhost:8081/jur/wildcardPermission @RequestMapping("wildcardPermission") public SaResult wildcardPermission() { // 前提条件:在 StpInterface 实现类中,为账号返回了 "art.*" 泛权限 StpUtil.hasPermission("art.add"); // 返回 true StpUtil.hasPermission("art.delete"); // 返回 true StpUtil.hasPermission("goods.add"); // 返回 false,因为前缀不符合 // * 符合可以出现在任意位置,比如权限码的开头,当账号拥有 "*.delete" 时 StpUtil.hasPermission("goods.add"); // false StpUtil.hasPermission("goods.delete"); // true StpUtil.hasPermission("art.delete"); // true // 也可以出现在权限码的中间,比如当账号拥有 "shop.*.user" 时 StpUtil.hasPermission("shop.add.user"); // true StpUtil.hasPermission("shop.delete.user"); // true StpUtil.hasPermission("shop.delete.goods"); // false,因为后缀不符合 // 注意点: // 1、上帝权限:当一个账号拥有 "*" 权限时,他可以验证通过任何权限码 // 2、角色校验也可以加 * ,指定泛角色,例如: "*.admin",暂不赘述 return SaResult.ok(); } }
代码注释已针对每一步操作做出详细解释,大家可根据可参照注释中的访问链接进行逐步测试。
以上是SpringBoot怎麼使用Sa-Token實作權限認證的詳細內容。更多資訊請關注PHP中文網其他相關文章!