晋江网站建设联系电话,温州网站建设培训学校,西安网站制作公司,wordpress首页显示文章一、设计思路
所谓权限认证#xff0c;核心逻辑就是判断一个账号是否拥有指定权限#xff1a;
有#xff0c;就让你通过。没有#xff1f;那么禁止访问#xff01;
深入到底层数据中#xff0c;就是每个账号都会拥有一个权限码集合#xff0c;框架来校验这个集合中是…一、设计思路
所谓权限认证核心逻辑就是判断一个账号是否拥有指定权限
有就让你通过。没有那么禁止访问
深入到底层数据中就是每个账号都会拥有一个权限码集合框架来校验这个集合中是否包含指定的权限码。
例如当前账号拥有权限码集合 [user-add, user-delete, user-get]这时候我来校验权限 user-update则其结果就是验证失败禁止访问。
动态演示图 所以现在问题的核心就是
如何获取一个账号所拥有的的权限码集合本次操作需要验证的权限码是哪个
接下来我们将介绍在 SpringBoot 中如何使用 Sa-Token 完成权限认证操作。 Sa-Token 是一个轻量级 java 权限认证框架主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。 Gitee 开源地址https://gitee.com/dromara/sa-token 首先在项目中引入 Sa-Token 依赖
!-- Sa-Token 权限认证 --
dependencygroupIdcn.dev33/groupIdartifactIdsa-token-spring-boot-starter/artifactIdversion1.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 {/*** 返回一个账号所拥有的权限码集合 */Overridepublic ListString getPermissionList(Object loginId, String loginType) {// 本list仅做模拟实际项目中要根据具体业务逻辑来查询权限ListString list new ArrayListString(); list.add(101);list.add(user.add);list.add(user.update);list.add(user.get);// list.add(user.delete);list.add(art.*);return list;}/*** 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)*/Overridepublic ListString getRoleList(Object loginId, String loginType) {// 本list仅做模拟实际项目中要根据具体业务逻辑来查询角色ListString list new ArrayListString(); list.add(admin);list.add(super-admin);return list;}}参数解释
loginId账号id即你在调用 StpUtil.login(id) 时写入的标识值。loginType账号体系标识此处可以暂时忽略在 [ 多账户认证 ] 章节下会对这个概念做详细的解释。
注意点 类上一定要加上 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());}
}然后就可以用以下api来鉴权了
// 获取当前账号所拥有的权限集合
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 抛出的异常
四、角色校验
在Sa-Token中角色和权限可以独立验证
// 获取当前账号所拥有的角色集合
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 {// 全局异常拦截 ExceptionHandlerpublic SaResult handlerException(Exception e) {e.printStackTrace(); return SaResult.error(e.getMessage());}
}六、权限通配符
Sa-Token允许你根据通配符指定泛权限例如当一个账号拥有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或其它全局状态管理对象中。在需要权限控制的按钮上使用 js 进行逻辑判断例如在Vue框架中我们可以使用如下写法
button v-ifarr.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?namezhangpwd123456* * 前提2项目实现 StpInterface 接口代码在 com.pj.satoken.StpInterfaceImpl* Sa-Token 将从此实现类获取 每个账号拥有哪些权限。* * 然后我们就可以使用以下示例中的代码进行鉴权了 */// 查询权限 ---- http://localhost:8081/jur/getPermissionRequestMapping(getPermission)public SaResult getPermission() {// 查询权限信息 如果当前会话未登录会返回一个空集合 ListString permissionList StpUtil.getPermissionList();System.out.println(当前登录账号拥有的所有权限 permissionList);// 查询角色信息 如果当前会话未登录会返回一个空集合 ListString roleList StpUtil.getRoleList();System.out.println(当前登录账号拥有的所有角色 roleList);// 返回给前端 return SaResult.ok().set(roleList, roleList).set(permissionList, permissionList);}// 权限校验 ---- http://localhost:8081/jur/checkPermissionRequestMapping(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/checkRoleRequestMapping(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/wildcardPermissionRequestMapping(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); // falseStpUtil.hasPermission(goods.delete); // trueStpUtil.hasPermission(art.delete); // true// 也可以出现在权限码的中间比如当账号拥有 shop.*.user 时 StpUtil.hasPermission(shop.add.user); // trueStpUtil.hasPermission(shop.delete.user); // trueStpUtil.hasPermission(shop.delete.goods); // false因为后缀不符合 // 注意点// 1、上帝权限当一个账号拥有 * 权限时他可以验证通过任何权限码// 2、角色校验也可以加 * 指定泛角色例如 *.admin暂不赘述 return SaResult.ok();}
}代码注释已针对每一步操作做出详细解释大家可根据可参照注释中的访问链接进行逐步测试。 参考资料
Sa-Token 文档https://sa-token.ccGitee 仓库地址https://gitee.com/dromara/sa-tokenGitHub 仓库地址https://github.com/dromara/sa-token