Sa-Token学习笔记-03
Sa-Token学习笔记-03
注解鉴权
尽管使用代码鉴权非常方便,但是我仍希望把鉴权逻辑和业务逻辑分离开来,我可以使用注解鉴权吗?当然可以!
注解鉴权 —— 优雅的将鉴权与业务代码分离!
@SaCheckLogin
:登陆校验 —— 只有登陆之后才能进入该方法。@SaCheckRole
:角色校验 —— 必须具有指定角色标识才能进入该方法。@SaCheckPermission("user.add")
:权限校验 —— 当前用户必须具有user.add
权限才可以访问2这个方法。@SaCheckSafe
:二级认证校验 —— 必须二级认证之后才可以进入该方法。@SaCheckHttpBasic
: HttpBasic校验 —— 只有通过 HttpBasic 认证后才能进入该方法。@SaCheckHttpDigest
: HttpDigest校验 —— 只有通过 HttpDigest 认证后才能进入该方法。@SaIgnore
:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。@SaCheckDisable("comment")
:账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。
将 Sa-Token 的全局拦截器注册到项目中
package com.hayaizo.satoken.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author moxiao
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册Sa-Token 拦截器,打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}
测试代码
package com.hayaizo.satoken.controller;
import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author moxiao
*/
@RestController
@RequestMapping("/at-check/")
public class AtCheckController {
/*
* 前提1:首先调用登录接口进行登录,代码在 com.pj.cases.use.LoginAuthController 中有详细解释,此处不再赘述
* ---- http://localhost:8081/acc/doLogin?username=zhang&password=123456
*
* 前提2:项目在配置类中注册拦截器 SaInterceptor ,代码在 com.hayaizo.satoken.config.SaTokenConfigure
* 此拦截器将打开注解鉴权功能
*
* 然后我们就可以使用以下示例中的代码进行注解鉴权了
*/
// 登录鉴权 ---- http://localhost:8081/at-check/checkLogin
// 登录认证后才可以进入方法
@SaCheckLogin
@RequestMapping("checkLogin")
public SaResult checkLogin(){
// 通过注解鉴权后才可以进入这个方法
return SaResult.ok("@SaCheckLogin鉴权通过");
}
// 权限校验 ---- http://localhost:8081/at-check/checkPermission
// 只有具有 user.add 权限的账号才可以进入方法
@SaCheckPermission("user.add")
@RequestMapping("checkPermission")
public SaResult checkPermission(){
// ...
return SaResult.ok();
}
// 权限校验2 ---- http://localhost:8081/at-check/checkPermission2
// 一次性校验多个权限,必须全部拥有,才可以进入方法
@SaCheckPermission(value = {"user.add","user.delete","user.update"},mode = SaMode.AND)
@RequestMapping("checkPermission2")
public SaResult checkPermission2(){
// ...
return SaResult.ok("\"user.add\",\"user.delete\",\"user.update\",AND");
}
// 权限校验3 ---- http://localhost:8081/at-check/checkPermission3
// 一次性校验多个权限,只要拥有其中一个,就可以进入方法
@SaCheckPermission(value = {"user.add","user.delete","user.update"},mode = SaMode.OR)
@RequestMapping("checkPermission3")
public SaResult checkPermission3(){
// ...
return SaResult.ok("\"user.add\",\"user.delete\",\"user.update\",OR");
}
// 角色校验 ---- http://localhost:8081/at-check/checkRole
// 只有具有 super-admin 角色的账号才可以进入方法
@SaCheckRole("super-admin")
@RequestMapping("checkRole")
public SaResult checkRole(){
// ...
return SaResult.ok();
}
// 角色权限双重 “or校验” ---- http://localhost:8081/at-check/userAdd
// 具备 "user.add"权限 或者 "admin"角色 即可通过校验
@SaCheckPermission(value = "user.add" , orRole = "admin")
@RequestMapping("userAdd")
public SaResult userAdd(){
// ...
return SaResult.data(StpUtil.getTokenInfo());
}
// 忽略校验 ---- http://localhost:8081/at-check/ignore
// 使用 @SaIgnore 修饰的方法,无需任何校验即可进入,具体使用示例可参照在线文档
@SaIgnore
@SaCheckLogin
@RequestMapping("ignore")
public SaResult ignore(){
// ...
return SaResult.ok();
}
}
路由拦截鉴权
给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。
在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式,那么在Sa-Token怎么实现路由拦截鉴权呢?
新建配置类SaTokenConfiguration.java
package com.hayaizo.satoken.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author moxiao
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handler -> {
// 跳过静态资源路径
SaRouter.match("/**")
.notMatch("/acc/doLogin")
.check(r -> StpUtil.checkLogin());
// 用户模块鉴权
SaRouter.match("/user/**", r -> StpUtil.checkPermissionOr("user", "admin"));
// 管理员模块鉴权
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
}).isAnnotation(false)).addPathPatterns("/**");
}
}
登出后再访问一些没有权限的接口试试。
匹配特征
// 基础写法样例:匹配一个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校验函数 */ );
提前退出匹配链
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匹配,直接进入Controller层
除了stop()
函数,SaRouter
还提供了 back()
函数,用于:停止匹配,结束执行,直接向前端返回结果
// 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端
SaRouter.match("/user/back").back("要返回到前端的内容");
stop() 与 back() 函数的区别在于:
SaRouter.stop()
会停止匹配,进入Controller。SaRouter.back()
会停止匹配,直接返回结果到前端。
free独立作用域
如果调用了stop之后还需要继续鉴权验证,可以使用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(/* --- */);
@SaIgnore忽略路由拦截校验
@SaIgnore
@RequestMapping("/user/getList")
public SaResult getList() {
System.out.println("------------ 访问进来方法");
return SaResult.ok();
}
注解 @SaIgnore
的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。
关闭注解校验
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new SaInterceptor(handle -> {
SaRouter.match("/**").check(r -> StpUtil.checkLogin());
}).isAnnotation(false) // 指定关闭掉注解鉴权能力,这样框架就只会做路由拦截校验了
).addPathPatterns("/**");
}
放行前端资源
package com.hayaizo.satoken.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author moxiao
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handler -> {
// 跳过静态资源路径
SaRouter.match("/**")
.notMatch("/acc/doLogin")
.notMatch("/*.html")
.notMatch("/*.js")
.notMatch("/*.css")
.notMatch("/*.jpeg")
.notMatch("/*.png")
.notMatch("/*.jpg")
.check(r -> StpUtil.checkLogin());
// 用户模块鉴权
SaRouter.match("/user/**", r -> StpUtil.checkPermissionOr("user", "admin"));
// 管理员模块鉴权
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
}).isAnnotation(false)).addPathPatterns("/**");
}
}
版权申明
本文系作者 @hayaizo 原创发布在Hello World站点。未经许可,禁止转载。
暂无评论数据