一、需求分析
在前文,咱们具体的叙述了在 Sa-Token 怎么运用注解进行权限认证,注解鉴权虽然便利,却并不适合一切鉴权场景。
假设有如下需求:项目中一切接口均需求登录认证校验,只有 “登录接口” 自身对外敞开。
假如咱们对项目一切接口都加上 @SaCheckLogin
注解,会显得非常冗余且没有必要,在这个需求中咱们真实需求的是一种依据路由阻拦的鉴权模式,那么在 Sa-Token 怎么完成路由阻拦鉴权呢?
Sa-Token 是一个轻量级 java 权限认证结构,主要处理登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。
Gitee 开源地址:gitee.com/dromara/sa-…
二、注册 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("/**");
}
参考资料
- Sa-Token 文档:sa-token.cc
- Gitee 库房地址:gitee.com/dromara/sa-…
- GitHub 库房地址:github.com/dromara/sa-…