一、需求分析

在前文,我们详细的讲述了在 Sa-Token 如何使用注解进行权限认证,注解鉴权虽然方便,却并不适合所有鉴权场景。

假设有如下需求:项目中所有接口均需要登录认证校验,只有 “登录接口” 本身对外开放。

如果我们对项目所有接口都加上 @SaCheckLogin 注解,会显得非常冗余且没有必要,在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式,那么在 Sa-Token 怎么实现路由拦截鉴权呢?

Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。

Gitee 开源地址:https://gitee.com/dromara/sa-token

二、注册 Sa-Token 路由拦截器

首先在项目中引入 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 即可。

新建配置类SaTokenConfigure.java

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns("/user/doLogin");
}
}

以上代码,我们注册了一个基于 StpUtil.checkLogin() 的登录校验拦截器,并且排除了/user/doLogin接口用来开放登录(除了/user/doLogin以外的所有接口都需要登录才能访问)。

SaInterceptor 是新版本提供的拦截器,点此 查看旧版本代码迁移示例

三、校验函数详解

自定义认证规则:new SaInterceptor(handle -> StpUtil.checkLogin()) 是最简单的写法,代表只进行登录校验功能。

我们可以往构造函数塞一个完整的 lambda 表达式,来定义详细的校验规则,例如:

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,定义详细认证规则
registry.addInterceptor(new SaInterceptor(handler -> {
// 指定一条 match 规则
SaRouter
.match("/**") // 拦截的 path 列表,可以写多个 */
.notMatch("/user/doLogin") // 排除掉的 path 列表,可以写多个
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式 // 根据路由划分模块,不同模块不同鉴权
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
})).addPathPatterns("/**");
}
}

SaRouter.match() 匹配函数有两个参数:

  • 参数一:要匹配的path路由。
  • 参数二:要执行的校验函数。

在校验函数内不只可以使用 StpUtil.checkPermission("xxx") 进行权限校验,你还可以写任意代码,例如:

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册 Sa-Token 的拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册路由拦截器,自定义认证规则
registry.addInterceptor(new SaInterceptor(handler -> { // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin()); // 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin")); // 权限校验 -- 不同模块校验不同权限
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment")); // 甚至你可以随意的写一个打印语句
SaRouter.match("/**", r -> System.out.println("----啦啦啦----")); // 连缀写法
SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----")); })).addPathPatterns("/**");
}
}

四、匹配特征详解

除了上述示例的 path 路由匹配,还可以根据很多其它特征进行匹配,以下是所有可匹配的特征:

// 基础写法样例:匹配一个path,执行一个校验函数
SaRouter.match("/user/**").check(r -> StpUtil.checkLogin()); // 根据 path 路由匹配 ——— 支持写多个path,支持写 restful 风格路由
// 功能说明: 使用 /user , /goods 或者 /art/get 开头的任意路由都将进入 check 方法
SaRouter.match("/user/**", "/goods/**", "/art/get/{id}").check( /* 要执行的校验函数 */ ); // 根据 path 路由排除匹配
// 功能说明: 使用 .html , .css 或者 .js 结尾的任意路由都将跳过, 不会进入 check 方法
SaRouter.match("/**").notMatch("*.html", "*.css", "*.js").check( /* 要执行的校验函数 */ ); // 根据请求类型匹配
SaRouter.match(SaHttpMethod.GET).check( /* 要执行的校验函数 */ ); // 根据一个 boolean 条件进行匹配
SaRouter.match( StpUtil.isLogin() ).check( /* 要执行的校验函数 */ ); // 根据一个返回 boolean 结果的lambda表达式匹配
SaRouter.match( r -> StpUtil.isLogin() ).check( /* 要执行的校验函数 */ ); // 多个条件一起使用
// 功能说明: 必须是 Get 请求 并且 请求路径以 `/user/` 开头
SaRouter.match(SaHttpMethod.GET).match("/user/**").check( /* 要执行的校验函数 */ ); // 可以无限连缀下去
// 功能说明: 同时满足 Get 方式请求, 且路由以 /admin 开头, 路由中间带有 /send/ 字符串, 路由结尾不能是 .js 和 .css
SaRouter
.match(SaHttpMethod.GET)
.match("/admin/**")
.match("/**/send/**")
.notMatch("/**/*.js")
.notMatch("/**/*.css")
// ....
.check( /* 只有上述所有条件都匹配成功,才会执行最后的check校验函数 */ );

五、提前退出匹配链

使用 SaRouter.stop() 可以提前退出匹配链,例:

registry.addInterceptor(new SaInterceptor(handler -> {
SaRouter.match("/**").check(r -> System.out.println("进入1"));
SaRouter.match("/**").check(r -> System.out.println("进入2")).stop();
SaRouter.match("/**").check(r -> System.out.println("进入3"));
SaRouter.match("/**").check(r -> System.out.println("进入4"));
SaRouter.match("/**").check(r -> System.out.println("进入5"));
})).addPathPatterns("/**");

如上示例,代码运行至第2条匹配链时,会在stop函数处提前退出整个匹配函数,从而忽略掉剩余的所有match匹配

除了stop()函数,SaRouter还提供了 back() 函数,用于:停止匹配,结束执行,直接向前端返回结果

// 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端
SaRouter.match("/user/back").back("要返回到前端的内容");

stop() 与 back() 函数的区别在于:

  • SaRouter.stop() 会停止匹配,进入Controller。
  • SaRouter.back() 会停止匹配,直接返回结果到前端。

六、使用free打开一个独立的作用域

// 进入 free 独立作用域
SaRouter.match("/**").free(r -> {
SaRouter.match("/a/**").check(/* --- */);
SaRouter.match("/b/**").check(/* --- */).stop();
SaRouter.match("/c/**").check(/* --- */);
});
// 执行 stop() 函数跳出 free 后继续执行下面的 match 匹配
SaRouter.match("/**").check(/* --- */);

free() 的作用是:打开一个独立的作用域,使内部的 stop() 不再一次性跳出整个 Auth 函数,而是仅仅跳出当前 free 作用域。

七、使用注解忽略掉路由拦截校验

我们可以使用 @SaIgnore 注解,忽略掉路由拦截认证:

1、先配置好了拦截规则:

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handler -> {
// 根据路由划分模块,不同模块不同鉴权
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
// ...
})).addPathPatterns("/**");
}

2、然后在 Controller 里又添加了忽略校验的注解

@SaIgnore
@RequestMapping("/user/getList")
public SaResult getList() {
System.out.println("------------ 访问进来方法");
return SaResult.ok();
}

请求将会跳过拦截器的校验,直接进入 Controller 的方法中。

注意点:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。

八、关闭注解校验

SaInterceptor 只要注册到项目中,默认就会打开注解校验,如果要关闭此能力,需要:

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new SaInterceptor(handle -> {
SaRouter.match("/**").check(r -> StpUtil.checkLogin());
}).isAnnotation(false) // 指定关闭掉注解鉴权能力,这样框架就只会做路由拦截校验了
).addPathPatterns("/**");
}

参考资料

SpringBoot 使用 Sa-Token 完成路由拦截鉴权的更多相关文章

  1. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  2. springboot+security整合(3)自定义鉴权

    说明 springboot 版本 2.0.3源码地址:点击跳转 系列 springboot+security 整合(1) springboot+security 整合(2) springboot+se ...

  3. iView 实战系列教程(21课时)_2.iView 实战教程之导航、路由、鉴权篇

    在c盘创建一个iview-router的项目 . 然后使用默认的配置 跳过 添加vue-router的插件 编译我们的文件. 编译好之后,我们启动App 默认的页面就打开了. 默认两个路由一个是abo ...

  4. 从零开始学YC-Framework之鉴权

    一.YC-Framework鉴权是基于哪一个开源框架做的? YC-Framework鉴权主要基于Dromara开源社区组织下的Sa-Token. 1.什么是Sa-Token? Sa-Token是一个轻 ...

  5. SpringBoot+JWT+SpringSecurity+MybatisPlus实现Restful鉴权脚手架

    若图片查看异常,请前往掘金查看:https://juejin.im/post/5d1dee34e51d4577790c1cf4 前言 JWT(json web token)的无状态鉴权方式,越来越流行 ...

  6. 【Spring Cloud & Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证授权.鉴权的逻辑,结合 ...

  7. JWT+Interceptor实现无状态登录和鉴权

    无状态登录原理 先提一下啥是有状态登录 单台tomcat的情况下:编码的流程如下 前端提交表单里用户的输入的账号密码 后台接受,查数据库, 在数据库中找到用户的信息后,把用户的信息存放到session ...

  8. HTTP基本认证和JWT鉴权

    一.HTTP基本认证 Basic Authentication——当浏览器访问使用基本认证的网站的时候, 浏览器会提示你输入用户名和密码. http auth的过程: · 客户端发送http请求 ·  ...

  9. JWT鉴权

    一.HTTP基本认证 Basic Authentication--当浏览器访问使用基本认证的网站的时候, 浏览器会提示你输入用户名和密码. http auth的过程: 客户端发送http请求 服务器发 ...

  10. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

随机推荐

  1. Less-7 '))闭合 和 secure_file_priv 配置写入一句话木马

    Less-7使用的文件导出select ... into outfile ....,一个文件上传. mysql安全配置里有一个配置secure_file_priv控制文件的导出导入. secure_f ...

  2. 取出预训练模型中间层的输出(pytorch)

    1 遍历子模块直接提取 对于简单的模型,可以采用直接遍历子模块的方法,取出相应name模块的输出,不对模型做任何改动.该方法的缺点在于,只能得到其子模块的输出,而对于使用nn.Sequensial() ...

  3. MySQL学习(一)大纲

    1.逻辑架构 参考博客:https://blog.csdn.net/fuzhongmin05/article/details/70904190 最上层为客户端层,并非mysql独有,诸如:连接处理.授 ...

  4. Tarjan强连通分量(scc)

    概念解释 节点强连通:\(v_i\)与\(v_j\)(\(v_i ≠ v_j\))强连通是指从\(vi\)到\(vj\)和从\(vj\)到\(vi\)都存在路径,即两节点互相可达 强连通图:在有向图\ ...

  5. Python 中 is 和 == 的区别

    is 和 == 的区别 相信学过 Python 小伙伴们都知道 is 和 == 都是用来比较 Python 对象的,但是区别就是 is 比较需要对象的值和内存地址都相等 == 比较只需要对象的值相等就 ...

  6. HTTP协议分析与Unity用法

    一.http协议简介 http协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网服务器传输超文本到本地浏览器的传送协议,使用TCP/IP通信协议传输 ...

  7. Stanford CS 144, Lab 0: networking warmup 实验

    Stanford CS 144, Lab 0: networking warmup Finish Stanford CS144 lab0 and pass the test. 2023/03/29 - ...

  8. vue中实用小技巧,长期更新

    1.在vue 中使用webpack require.context工程化配置组件,不用一个一个import注册了 main.js中 import Vue from 'vue'//使用lodsh插件im ...

  9. nginx重启和操作

    在linux操作系统中,重启nginx 1.当不知道nginx所在目录时,需要先查找到nginx的位置  查看ngnix位置(master process 后面的就是 nginx的目录): ps -e ...

  10. 干掉复杂的工具类,国产Java工具类库 Hutool 很香!

    Hutool 大家已经比较熟悉了,这是一个超全的 Java 工具库,深受国内开发者的喜爱. 我之前其实是不太喜欢使用这种功能太多的工具类的,也比较担心稳定性和安全性,后面慢慢接受了就感觉其实也还好.而 ...