From c3bedaef99d748f7810a69aed19d53d022cb7de9 Mon Sep 17 00:00:00 2001 From: shengzhang <2393584716@qq.com> Date: Mon, 11 Jan 2021 20:08:17 +0800 Subject: [PATCH] =?UTF-8?q?v.1.12.0=E6=96=B0=E7=89=B9=E6=80=A7=EF=BC=9A?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E6=8B=A6=E6=88=AA=E5=BC=8F=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pj/satoken/MySaTokenConfig.java | 5 +- .../main/java/com/pj/test/TestController.java | 10 +- sa-token-doc/doc/_sidebar.md | 1 + sa-token-doc/doc/use/at-check.md | 23 +- sa-token-doc/doc/use/route-check.md | 80 ++++++ ...ptor.java => SaAnnotationInterceptor.java} | 40 +-- .../dev33/satoken/interceptor/SaFunction.java | 15 ++ .../interceptor/SaRouteInterceptor.java | 250 ++++++++++++++++++ 8 files changed, 383 insertions(+), 41 deletions(-) create mode 100644 sa-token-doc/doc/use/route-check.md rename sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/{SaCheckInterceptor.java => SaAnnotationInterceptor.java} (66%) create mode 100644 sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaFunction.java create mode 100644 sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java diff --git a/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java b/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java index c5fc7823..c3322b38 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java @@ -5,7 +5,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import cn.dev33.satoken.config.SaTokenConfig; -import cn.dev33.satoken.interceptor.SaCheckInterceptor; +import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; /** * sa-token代码方式进行配置 @@ -30,7 +30,8 @@ public class MySaTokenConfig implements WebMvcConfigurer { // 注册sa-token的拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new SaCheckInterceptor()).addPathPatterns("/**"); // 全局拦截器 + // 注册注解拦截器 + registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); // 全局拦截器 } diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index e47642d8..523e61a8 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -234,8 +234,14 @@ public class TestController { // 测试 浏览器访问: http://localhost:8081/test/test @RequestMapping("test") public AjaxJson test() { - StpUtil.getTokenSession().logout(); - StpUtil.logoutByLoginId(10001); +// StpUtil.getTokenSession().logout(); +// StpUtil.logoutByLoginId(10001); + return AjaxJson.getSuccess(); + } + + // 测试 浏览器访问: http://localhost:8081/test/test2 + @RequestMapping("test2") + public AjaxJson test2() { return AjaxJson.getSuccess(); } diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index f6d1b079..5132b68d 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -16,6 +16,7 @@ - [多账号验证](/use/many-account) - [同端互斥登录](/use/mutex-login) - [注解式鉴权](/use/at-check) + - [路由拦截式鉴权](/use/route-check) - [花式token](/use/token-style) - [框架配置](/use/config) - [会话治理](/use/search-session) diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md index 3f7cf06a..0fbb12fe 100644 --- a/sa-token-doc/doc/use/at-check.md +++ b/sa-token-doc/doc/use/at-check.md @@ -13,10 +13,10 @@ ``` java @Configuration public class MySaTokenConfig implements WebMvcConfigurer { - // 注册sa-token的拦截器,打开注解式鉴权功能 + // 注册sa-token的注解拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new SaCheckInterceptor()).addPathPatterns("/**"); // 全局拦截器 + registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); } } ``` @@ -119,22 +119,3 @@ public class UserService { - - - - - - diff --git a/sa-token-doc/doc/use/route-check.md b/sa-token-doc/doc/use/route-check.md new file mode 100644 index 00000000..389a1340 --- /dev/null +++ b/sa-token-doc/doc/use/route-check.md @@ -0,0 +1,80 @@ +# 路由拦截式鉴权 +--- + +假设我们有如下需求: +> 项目中所有接口均需要登录验证,只有'登录接口'本身对外开放 + +我们怎么实现呢?给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。
+在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式, 那么在sa-token怎么实现路由拦截鉴权呢? + + + +## 1、注册路由拦截器 +以`springboot2.0`为例, 新建配置类`MySaTokenConfig.java` +``` java +@Configuration +public class MySaTokenConfig implements WebMvcConfigurer { + // 注册sa-token的登录拦截器 + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册登录拦截器,并排除登录接口地址 + registry.addInterceptor(new SaRouteInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/doLogin"); + } +} +``` +以上代码,我们注册了一个登录验证拦截器,并且排除了`/user/doLogin`接口用来开放登录
+那么我们如何进行权限认证拦截呢,且往下看 + + +## 2、所有拦截器示例 +``` java +@Configuration +public class MySaTokenConfig implements WebMvcConfigurer { + // 注册sa-token的所有拦截器 + @Override + public void addInterceptors(InterceptorRegistry registry) { + + // 注册一个登录验证拦截器 + registry.addInterceptor(SaRouteInterceptor.createLoginVal()).addPathPatterns("/**").excludePathPatterns("/user/doLogin"); + + // 注册一个角色认证拦截器 + registry.addInterceptor(SaRouteInterceptor.createRoleVal("super-admin")).addPathPatterns("/**"); + + // 注册一个权限认证拦截器 + registry.addInterceptor(SaRouteInterceptor.createPermissionVal("user:add", "user:deelete")).addPathPatterns("/UserController/**"); + + // 注册一个自定义认证拦截器 (可以写任意认证代码) + registry.addInterceptor(new SaRouteInterceptor(new SaFunction() { + @Override + public void run() { + // 你可以写任意认证代码, 例如: StpUtil.checkLogin(); + System.out.println("---------- 进入自定义认证 --------------- "); + } + })).addPathPatterns("/**"); + + /** ------ 如果你使用的JDK版本是1.8或以上,上面那一坨可以简写为以下形式 ------ */ + + // 注册一个自定义认证拦截器 (可以写任意认证代码) + registry.addInterceptor(new SaRouteInterceptor(()->{ + // 你可以写任意认证代码, 例如: StpUtil.checkLogin(); + System.out.println("---------- 进入自定义认证2 --------------- "); + })).addPathPatterns("/**"); + + } +} +``` +(你不必像上面的示例一样注册所有拦截器,只要按需注册即可 ) + + +## 3、所有拦截器示例 + + + + + + + + + + + diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java similarity index 66% rename from sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java rename to sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java index 1ab9aba2..1123bfb2 100644 --- a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java @@ -15,7 +15,7 @@ import cn.dev33.satoken.stp.StpUtil; * 注解式鉴权 - 拦截器 * @author kong */ -public class SaCheckInterceptor implements HandlerInterceptor { +public class SaAnnotationInterceptor implements HandlerInterceptor { /** @@ -24,23 +24,32 @@ public class SaCheckInterceptor implements HandlerInterceptor { public StpLogic stpLogic = null; /** - * 创建,并指定一个默认的 StpLogic + * @return 底层的 StpLogic 对象 */ - public SaCheckInterceptor() { - this(StpUtil.stpLogic); + public StpLogic getStpLogic() { + if(stpLogic == null) { + stpLogic = StpUtil.stpLogic; + } + return stpLogic; } - - /** - * 创建,并指定一个的 StpLogic - * @param stpLogic 指定的StpLogic - */ - public SaCheckInterceptor(StpLogic stpLogic) { - this.stpLogic = stpLogic; - } - /** - * 每次请求之前触发 + * @param stpLogic 底层的 StpLogic 对象 + */ + public SaAnnotationInterceptor setStpLogic(StpLogic stpLogic) { + this.stpLogic = stpLogic; + return this; + } + + + /** + * 创建,并指定一个默认的 StpLogic + */ + public SaAnnotationInterceptor() { + } + + /** + * 每次请求之前触发的方法 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) @@ -53,7 +62,7 @@ public class SaCheckInterceptor implements HandlerInterceptor { Method method = ((HandlerMethod) handler).getMethod(); // 进行验证 - stpLogic.checkMethodAnnotation(method); + getStpLogic().checkMethodAnnotation(method); // 通过验证 return true; @@ -61,5 +70,4 @@ public class SaCheckInterceptor implements HandlerInterceptor { - } diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaFunction.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaFunction.java new file mode 100644 index 00000000..25f59464 --- /dev/null +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaFunction.java @@ -0,0 +1,15 @@ +package cn.dev33.satoken.interceptor; + +/** + * 执行验证方法的辅助类 + * @author kong + * + */ +public interface SaFunction { + + /** + * 执行验证的方法 + */ + public void run(); + +} diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java new file mode 100644 index 00000000..5f688c12 --- /dev/null +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaRouteInterceptor.java @@ -0,0 +1,250 @@ +package cn.dev33.satoken.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerInterceptor; + +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.stp.StpUtil; + +/** + * sa-token基于路由的拦截式鉴权 + * @author kong + */ +public class SaRouteInterceptor implements HandlerInterceptor { + + + // ----------------- 属性 ----------------- + + /** + * 底层的 StpLogic 对象 + */ + private StpLogic stpLogic; + + /** + * 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证) + */ + private int type; + + /** + * 验证模式 AND | OR + */ + private SaMode mode; + + /** + * 标识码数组 + */ + private String[] codes; + + /** + * 自定义模式下的执行函数 + */ + private SaFunction function; + + + /** + * 表示登录验证 + */ + public static final int LOGIN = 1; + + /** + * 表示角色验证 + */ + public static final int ROLE = 2; + + /** + * 表示权限验证 + */ + public static final int PERMISSION = 3; + + /** + * 表示自定义验证 + */ + public static final int CUSTOM = 4; + + + /** + * @return 底层的 StpLogic 对象 + */ + public StpLogic getStpLogic() { + if(stpLogic == null) { + stpLogic = StpUtil.stpLogic; + } + return stpLogic; + } + + /** + * @param stpLogic 底层的 StpLogic 对象 + */ + public SaRouteInterceptor setStpLogic(StpLogic stpLogic) { + this.stpLogic = stpLogic; + return this; + } + + /** + * @return 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证) + */ + public int getType() { + return type; + } + + /** + * @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证) + */ + public SaRouteInterceptor setType(int type) { + this.type = type; + return this; + } + + /** + * @return 验证模式 AND | OR + */ + public SaMode getMode() { + return mode; + } + + /** + * @param mode 验证模式 AND | OR + */ + public SaRouteInterceptor setMode(SaMode mode) { + this.mode = mode; + return this; + } + + /** + * @return 标识码数组 + */ + public String[] getCodes() { + return codes; + } + + /** + * @param codes 标识码数组 + */ + public SaRouteInterceptor setCodes(String... codes) { + this.codes = codes; + return this; + } + + /** + * @return 自定义模式下的执行函数 + */ + public SaFunction getFunction() { + return function; + } + + /** + * @param function 设置自定义模式下的执行函数 + */ + public SaRouteInterceptor setFunction(SaFunction function) { + this.type = SaRouteInterceptor.CUSTOM; + this.function = function; + return this; + } + + + // ----------------- 构建相关 ----------------- + + /** + * 创建 (全参数) + * @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证) + * @param mode 验证模式 AND | OR + * @param codes 标识码数组 + */ + public SaRouteInterceptor(int type, SaMode mode, String... codes) { + super(); + this.type = type; + this.mode = mode; + this.codes = codes; + } + + /** + * 创建 (默认为登录验证) + */ + public SaRouteInterceptor() { + this(SaRouteInterceptor.LOGIN, null, new String[0]); + } + + /** + * 创建 (默认为自定义认证) + * @param function 自定义模式下的执行函数 + */ + public SaRouteInterceptor(SaFunction function) { + this(SaRouteInterceptor.CUSTOM, null, new String[0]); + setFunction(function); + } + + /** + * 构建一个模式为登录认证的sa路由拦截器 + * @return sa拦截器 + */ + public static SaRouteInterceptor createLoginVal() { + return new SaRouteInterceptor(); + } + + /** + * 构建一个模式为角色认证的sa路由拦截器 + * @param roles 需要验证的数组标识列表 + * @return sa拦截器 + */ + public static SaRouteInterceptor createRoleVal(String... roles) { + return new SaRouteInterceptor(SaRouteInterceptor.ROLE, SaMode.AND, roles); + } + + /** + * 构建一个模式为权限认证的sa路由拦截器 + * @param permissions 需要验证的数组权限列表 + * @return sa拦截器 + */ + public static SaRouteInterceptor createPermissionVal(String... permissions) { + return new SaRouteInterceptor(SaRouteInterceptor.PERMISSION, SaMode.AND, permissions); + } + + /** + * 创建一个模式为自定义认证的sa路由拦截器 + * @param function 自定义模式下的执行函数 + * @return sa拦截器 + */ + public static SaRouteInterceptor createCustomVal(SaFunction function) { + return new SaRouteInterceptor(function); + } + + + // ----------------- 验证方法 ----------------- + + /** + * 每次请求之前触发的方法 + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + // 根据模式进行验证 + if(this.type == SaRouteInterceptor.LOGIN) { + getStpLogic().checkLogin(); + } else if(this.type == SaRouteInterceptor.ROLE) { + if(mode == SaMode.AND) { + getStpLogic().checkRoleAnd(codes); + } else { + getStpLogic().checkRoleOr(codes); + } + } else if(this.type == SaRouteInterceptor.PERMISSION) { + if(mode == SaMode.AND) { + getStpLogic().checkPermissionAnd(codes); + } else { + getStpLogic().checkPermissionOr(codes); + } + } else if(this.type == SaRouteInterceptor.CUSTOM) { + function.run(); + } + + // 通过验证 + return true; + } + + + + +}