
大家好,我是 NEO。
在做 Web 开发时,权限认证是一个绕不开的话题。它的核心逻辑其实非常简单:规定哪些用户可以访问哪些接口、页面或资源。

虽然逻辑简单,但很多框架配置起来却异常繁琐。今天我们就来看看,如何使用 Sa-Token 这个轻量级框架,优雅地搞定权限认证。
框架是如何判断一个账号是否有权访问某个接口的呢?
从底层数据来看,逻辑是这样的:每个账号都拥有一组“权限码集合”,框架要做的,就是校验这个集合中是否包含当前接口要求的权限码。
所以,问题的核心就变成了两个:

在进行校验之前,你需要先实现 StpInterface 接口。这一步的作用是连接你的数据库,告诉 Sa-Token 指定账号到底拥有哪些权限。
新建一个类 StpInterfaceImpl,并注入到 Spring 容器中:
/**
* 自定义权限加载接口实现类
*/
@Component // 保证此类被 SpringBoot 扫描,完成 Sa-Token 的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一个账号所拥有的权限码集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 模拟数据,实际项目中请查询数据库
List<String> list = new ArrayList<String>();
list.add("101");
list.add("user.add");
list.add("user.update");
list.add("user.get");
list.add("art.*"); // 支持通配符
return list;
}
/**
* 返回一个账号所拥有的角色标识集合
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 模拟数据
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}参数解释:
StpUtil.login(id) 时写入的唯一标识值。有同学经常问的一个问题:
“我实现了这个接口,为什么程序启动时没执行?”
答: 这是正常的。该方法只有在每次调用鉴权代码时才会被执行,属于懒加载模式,不用担心性能浪费。
准备工作做好了,现在可以在代码中进行鉴权了。Sa-Token 提供了极其简洁的 API:
1. 权限校验
// 获取:当前账号所拥有的权限集合
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 抛出的异常
2. 角色校验
角色和权限是完全独立的,用法几乎一致:
// 获取:当前账号所拥有的角色集合
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 抛出的异常
3. 进阶:权限通配符
Sa-Token 支持强大的泛权限匹配。
例如,如果一个账号拥有 art.* 的权限,那么:
art.add -> 通过art.delete -> 通过goods.add -> 不通过如果是超级管理员,可以直接给一个 * 权限,他将能够通过所有校验。
鉴权失败时,框架会抛出 NotPermissionException。如果把这个异常直接展示给用户,体验非常差。
我们需要做一个全局异常拦截器,统一返回 JSON 格式的错误信息:
@RestControllerAdvice
public class GlobalExceptionHandler {
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
// 返回友好的错误提示
return SaResult.error(e.getMessage());
}
}这样,前端收到的就是一个标准的 { code: 500, msg: "无此权限" },而不是一大堆报错堆栈。
经常有需求问:“我不仅要拦截接口,还要控制页面上的按钮是否显示,该怎么做?”

这需要前后端配合完成:
localStorage 或 Vuex/Pinia 中。如果是前后端一体项目,可以参考:Thymeleaf 标签方言[1],如果是前后端分离项目,则:
以 Vue 为例:
<!-- arr 是当前用户的权限码数组 -->
<div>
<button v-if="arr.includes('user.get')">查询用户</button>
<button v-if="arr.includes('user.update')">修改用户</button>
<button v-if="arr.includes('user.delete')">删除按钮</button>
</div>以上写法只为提供一个参考示例,不同框架有不同写法,大家可根据项目技术栈灵活封装进行调用。
特别提醒:
前端的鉴权只是为了提升用户体验(看不见的按钮点不了)。为了安全,后端接口必须再次进行 StpUtil.checkPermission() 校验,永远不要相信前端传来的请求!
写在最后
权限认证是后端系统的基石,Sa-Token 通过极简的设计,把这个复杂问题变得像写 if-else 一样简单。
如果你觉得这篇文章对你有帮助,欢迎点赞、在看、转发,这对我很重要!
我们下期见。
相关文章推荐:
[1] Thymeleaf 标签方言: https://sa-token.cc/doc.html#/plugin/thymeleaf-extend
如果这篇文章帮到了你,不妨点个分享给同样需要的朋友吧! 你的每一次支持,都是我持续创作的动力!💪