From 46e3317c1fa7bc2375a6ee39162a7d7aac709b01 Mon Sep 17 00:00:00 2001 From: noear Date: Tue, 12 Jul 2022 13:55:30 +0800 Subject: [PATCH] =?UTF-8?q?sa-token-solon-plugin=EF=BC=9A=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=20solon=20=E4=B8=BA=201.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-token-demo/sa-token-demo-solon/pom.xml | 2 +- .../sa-token-solon-plugin/pom.xml | 2 +- .../cn/dev33/satoken/solon/XPluginImp.java | 14 +- ...java => SaTokenAnnotationInterceptor.java} | 4 +- .../solon/integration/SaTokenPathFilter.java | 62 ++++-- .../integration/SaTokenPathInterceptor.java | 183 ++++++++++++++++++ .../SaContextForSolon.java | 2 +- .../src/test/java/demo/App.java | 12 ++ .../src/test/java/demo/Config.java | 41 ++++ .../src/test/java/demo2/App.java | 12 ++ .../src/test/java/demo2/Config.java | 53 +++++ .../src/test/resources/app.yml | 26 +++ 12 files changed, 383 insertions(+), 30 deletions(-) rename sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/{SaTokenMethodInterceptor.java => SaTokenAnnotationInterceptor.java} (74%) create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java rename sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/{integration => model}/SaContextForSolon.java (96%) create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java create mode 100644 sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml diff --git a/sa-token-demo/sa-token-demo-solon/pom.xml b/sa-token-demo/sa-token-demo-solon/pom.xml index 21857a8d..0f803e9f 100644 --- a/sa-token-demo/sa-token-demo-solon/pom.xml +++ b/sa-token-demo/sa-token-demo-solon/pom.xml @@ -18,7 +18,7 @@ org.noear solon-web - 1.9.1 + 1.9.2 diff --git a/sa-token-starter/sa-token-solon-plugin/pom.xml b/sa-token-starter/sa-token-solon-plugin/pom.xml index cc9e876a..0f44b91d 100644 --- a/sa-token-starter/sa-token-solon-plugin/pom.xml +++ b/sa-token-starter/sa-token-solon-plugin/pom.xml @@ -20,7 +20,7 @@ org.noear solon - 1.9.1 + 1.9.2 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index 65823601..1e7a9786 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -16,8 +16,8 @@ import cn.dev33.satoken.id.SaIdUtil; import cn.dev33.satoken.json.SaJsonTemplate; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.sign.SaSignTemplate; -import cn.dev33.satoken.solon.integration.SaContextForSolon; -import cn.dev33.satoken.solon.integration.SaTokenMethodInterceptor; +import cn.dev33.satoken.solon.model.SaContextForSolon; +import cn.dev33.satoken.solon.integration.SaTokenAnnotationInterceptor; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; @@ -31,11 +31,11 @@ public class XPluginImp implements Plugin { @Override public void start(AopContext context) { - context.beanAroundAdd(SaCheckPermission.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckRole.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckLogin.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckSafe.class, SaTokenMethodInterceptor.INSTANCE); - context.beanAroundAdd(SaCheckBasic.class, SaTokenMethodInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckPermission.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckRole.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckLogin.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckSafe.class, SaTokenAnnotationInterceptor.INSTANCE); + context.beanAroundAdd(SaCheckBasic.class, SaTokenAnnotationInterceptor.INSTANCE); //集成初始化 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java similarity index 74% rename from sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java rename to sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java index 950b05e2..2f73754c 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenMethodInterceptor.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenAnnotationInterceptor.java @@ -9,9 +9,9 @@ import cn.dev33.satoken.strategy.SaStrategy; * @author noear * @since 1.4 */ -public class SaTokenMethodInterceptor implements Interceptor { +public class SaTokenAnnotationInterceptor implements Interceptor { - public static final SaTokenMethodInterceptor INSTANCE = new SaTokenMethodInterceptor(); + public static final SaTokenAnnotationInterceptor INSTANCE = new SaTokenAnnotationInterceptor(); @Override public Object doIntercept(Invocation inv) throws Throwable { diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java index 6014aca8..ef5e760e 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathFilter.java @@ -1,12 +1,12 @@ package cn.dev33.satoken.solon.integration; - import cn.dev33.satoken.exception.BackResultException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.exception.StopMatchException; import cn.dev33.satoken.filter.SaFilterAuthStrategy; import cn.dev33.satoken.filter.SaFilterErrorStrategy; import cn.dev33.satoken.router.SaRouter; +import org.noear.solon.Utils; import org.noear.solon.core.handle.Context; import org.noear.solon.core.handle.Filter; import org.noear.solon.core.handle.FilterChain; @@ -16,24 +16,26 @@ import java.util.Arrays; import java.util.List; /** - * @author noear 2021/5/30 created + * @author noear + * @since 1.9 */ public class SaTokenPathFilter implements Filter { - + // ------------------------ 设置此过滤器 拦截 & 放行 的路由 /** * 拦截路由 */ - private List includeList = new ArrayList<>(); + protected List includeList = new ArrayList<>(); /** * 放行路由 */ - private List excludeList = new ArrayList<>(); + protected List excludeList = new ArrayList<>(); /** * 添加 [拦截路由] + * * @param paths 路由 * @return 对象自身 */ @@ -44,6 +46,7 @@ public class SaTokenPathFilter implements Filter { /** * 添加 [放行路由] + * * @param paths 路由 * @return 对象自身 */ @@ -54,6 +57,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入 [拦截路由] 集合 + * * @param pathList 路由集合 * @return 对象自身 */ @@ -64,6 +68,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入 [放行路由] 集合 + * * @param pathList 路由集合 * @return 对象自身 */ @@ -74,6 +79,7 @@ public class SaTokenPathFilter implements Filter { /** * 获取 [拦截路由] 集合 + * * @return see note */ public List getIncludeList() { @@ -82,6 +88,7 @@ public class SaTokenPathFilter implements Filter { /** * 获取 [放行路由] 集合 + * * @return see note */ public List getExcludeList() { @@ -94,22 +101,29 @@ public class SaTokenPathFilter implements Filter { /** * 认证函数:每次请求执行 */ - public SaFilterAuthStrategy auth = r -> {}; + protected SaFilterAuthStrategy auth = r -> { + }; /** * 异常处理函数:每次[认证函数]发生异常时执行此函数 */ - public SaFilterErrorStrategy error = e -> { - throw new SaTokenException(e); + protected SaFilterErrorStrategy error = e -> { + if (e instanceof SaTokenException) { + throw (SaTokenException) e; + } else { + throw new SaTokenException(e); + } }; /** * 前置函数:在每次[认证函数]之前执行 */ - public SaFilterAuthStrategy beforeAuth = r -> {}; + protected SaFilterAuthStrategy beforeAuth = r -> { + }; /** * 写入[认证函数]: 每次请求执行 + * * @param auth see note * @return 对象自身 */ @@ -120,6 +134,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入[异常处理函数]:每次[认证函数]发生异常时执行此函数 + * * @param error see note * @return 对象自身 */ @@ -130,6 +145,7 @@ public class SaTokenPathFilter implements Filter { /** * 写入[前置函数]:在每次[认证函数]之前执行 + * * @param beforeAuth see note * @return 对象自身 */ @@ -144,23 +160,33 @@ public class SaTokenPathFilter implements Filter { try { // 执行全局过滤器 SaRouter.match(includeList).notMatch(excludeList).check(r -> { - beforeAuth.run(null); + beforeAuth.run(null); auth.run(null); }); - + } catch (StopMatchException e) { - - } catch (Throwable e) { - // 1. 获取异常处理策略结果 - String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e)); + + } catch (SaTokenException e) { + // 1. 获取异常处理策略结果 + Object result; + if (e instanceof BackResultException) { + result = e.getMessage(); + } else { + result = error.run(e); + } // 2. 写入输出流 - ctx.contentType("text/plain; charset=utf-8"); - ctx.output(result); + if(result != null) { + ctx.render(result); + } + ctx.setHandled(true); return; + } catch (Throwable e) { + // 异常解包 + throw Utils.throwableUnwrap(e); //solon 的最后层还有保底处理 } // 执行 chain.doFilter(ctx); } -} +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java new file mode 100644 index 00000000..b89adca0 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenPathInterceptor.java @@ -0,0 +1,183 @@ +package cn.dev33.satoken.solon.integration; + +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.filter.SaFilterAuthStrategy; +import cn.dev33.satoken.filter.SaFilterErrorStrategy; +import cn.dev33.satoken.router.SaRouter; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Handler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * sa-token基于路由的拦截式鉴权 + * @author kong + */ +public class SaTokenPathInterceptor implements Handler { + + // ------------------------ 设置此过滤器 拦截 & 放行 的路由 + + /** + * 拦截路由 + */ + protected List includeList = new ArrayList<>(); + + /** + * 放行路由 + */ + protected List excludeList = new ArrayList<>(); + + /** + * 添加 [拦截路由] + * + * @param paths 路由 + * @return 对象自身 + */ + public SaTokenPathInterceptor addInclude(String... paths) { + includeList.addAll(Arrays.asList(paths)); + return this; + } + + /** + * 添加 [放行路由] + * + * @param paths 路由 + * @return 对象自身 + */ + public SaTokenPathInterceptor addExclude(String... paths) { + excludeList.addAll(Arrays.asList(paths)); + return this; + } + + /** + * 写入 [拦截路由] 集合 + * + * @param pathList 路由集合 + * @return 对象自身 + */ + public SaTokenPathInterceptor setIncludeList(List pathList) { + includeList = pathList; + return this; + } + + /** + * 写入 [放行路由] 集合 + * + * @param pathList 路由集合 + * @return 对象自身 + */ + public SaTokenPathInterceptor setExcludeList(List pathList) { + excludeList = pathList; + return this; + } + + /** + * 获取 [拦截路由] 集合 + * + * @return see note + */ + public List getIncludeList() { + return includeList; + } + + /** + * 获取 [放行路由] 集合 + * + * @return see note + */ + public List getExcludeList() { + return excludeList; + } + + + // ------------------------ 钩子函数 + + /** + * 认证函数:每次请求执行 + */ + protected SaFilterAuthStrategy auth = r -> { + }; + + /** + * 异常处理函数:每次[认证函数]发生异常时执行此函数 + */ + protected SaFilterErrorStrategy error = e -> { + if (e instanceof SaTokenException) { + throw (SaTokenException) e; + } else { + throw new SaTokenException(e); + } + }; + + /** + * 前置函数:在每次[认证函数]之前执行 + */ + protected SaFilterAuthStrategy beforeAuth = r -> { + }; + + /** + * 写入[认证函数]: 每次请求执行 + * + * @param auth see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setAuth(SaFilterAuthStrategy auth) { + this.auth = auth; + return this; + } + + /** + * 写入[异常处理函数]:每次[认证函数]发生异常时执行此函数 + * + * @param error see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setError(SaFilterErrorStrategy error) { + this.error = error; + return this; + } + + /** + * 写入[前置函数]:在每次[认证函数]之前执行 + * + * @param beforeAuth see note + * @return 对象自身 + */ + public SaTokenPathInterceptor setBeforeAuth(SaFilterAuthStrategy beforeAuth) { + this.beforeAuth = beforeAuth; + return this; + } + + + @Override + public void handle(Context ctx) throws Throwable { + try { + // 执行全局过滤器 + SaRouter.match(includeList).notMatch(excludeList).check(r -> { + beforeAuth.run(null); + auth.run(null); + }); + + } catch (StopMatchException e) { + + } catch (SaTokenException e) { + // 1. 获取异常处理策略结果 + Object result; + if (e instanceof BackResultException) { + result = e.getMessage(); + } else { + result = error.run(e); + } + + // 2. 写入输出流 + if(result != null) { + ctx.render(result); + } + ctx.setHandled(true); + } + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java similarity index 96% rename from sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java rename to sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java index e372aa01..e6ef1cc6 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaContextForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java @@ -1,4 +1,4 @@ -package cn.dev33.satoken.solon.integration; +package cn.dev33.satoken.solon.model; import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.context.model.SaRequest; diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java new file mode 100644 index 00000000..ac68f579 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/App.java @@ -0,0 +1,12 @@ +package demo; + +import org.noear.solon.Solon; + +/** + * @author noear 2022/3/30 created + */ +public class App { + public static void main(String[] args) { + Solon.start(App.class, args); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java new file mode 100644 index 00000000..8bd221b1 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo/Config.java @@ -0,0 +1,41 @@ +package demo; + +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.solon.integration.SaTokenPathFilter; +import cn.dev33.satoken.stp.StpUtil; +import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Configuration; +import org.noear.solon.core.handle.Filter; + +/** + * @author noear 2022/3/30 created + */ +@Configuration +public class Config { + + @Bean + public Filter saTokenFilter() { + return new SaTokenPathFilter() + // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**").addExclude("/favicon.ico") + + // 认证函数: 每次请求执行 + .setAuth(s -> { + SaRouter.match("/**", StpUtil::checkLogin); + + // 根据路由划分模块,不同模块不同鉴权 + 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")); + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + System.out.println("---------- sa全局异常 "); + System.out.println(e.getMessage()); + StpUtil.login(123); + return e.getMessage(); + }); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java new file mode 100644 index 00000000..8b9ff8b5 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/App.java @@ -0,0 +1,12 @@ +package demo2; + +import org.noear.solon.Solon; + +/** + * @author noear 2022/3/30 created + */ +public class App { + public static void main(String[] args) { + Solon.start(App.class, args); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java new file mode 100644 index 00000000..7b970b72 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/java/demo2/Config.java @@ -0,0 +1,53 @@ +package demo2; + +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.solon.integration.SaTokenPathInterceptor; +import cn.dev33.satoken.stp.StpUtil; +import org.noear.solon.Solon; +import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Configuration; + +/** + * @author noear 2022/7/11 created + */ +@Configuration +public class Config { + @Bean + public void saTokenPathInterceptor() { + Solon.app().before(new SaTokenPathInterceptor() + // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**").addExclude("/favicon.ico") + + // 认证函数: 每次请求执行 + .setAuth(s -> { + SaRouter.match("/**", StpUtil::checkLogin); + + // 根据路由划分模块,不同模块不同鉴权 + 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")); + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + System.out.println("---------- sa全局异常 "); + System.out.println(e.getMessage()); + StpUtil.login(123); + return e.getMessage(); + }) + ); + } + + @Bean + public void saTokenPathInterceptor2() { + Solon.app().before((ctx) -> { + SaRouter.match("/**", StpUtil::checkLogin); + // 根据路由划分模块,不同模块不同鉴权 + 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")); + }); + } +} diff --git a/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml b/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml new file mode 100644 index 00000000..5dd15890 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/test/resources/app.yml @@ -0,0 +1,26 @@ + + +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + allow-concurrent-login: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: true + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false + + +sa-token-dao: #名字可以随意取 + redis: + server: "localhost:6379" + password: 123456 + db: 1 + maxTotal: 200