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;
+ }
+
+
+
+
+}