plugins) {
+ for (SaTokenPlugin plugin : plugins) {
+ SaTokenPluginHolder.instance.installPlugin(plugin);
+ }
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/SaBeanRegister.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/SaBeanRegister.java
new file mode 100644
index 00000000..7b18256f
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/SaBeanRegister.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot;
+
+import cn.dev33.satoken.config.SaTokenConfig;
+import cn.dev33.satoken.loveqq.boot.context.path.ApplicationContextPathLoading;
+import cn.dev33.satoken.loveqq.boot.filter.SaFirewallCheckFilter;
+import cn.dev33.satoken.loveqq.boot.filter.SaTokenContextFilter;
+import cn.dev33.satoken.loveqq.boot.filter.SaTokenCorsFilter;
+import cn.dev33.satoken.loveqq.boot.support.SaPathMatcherHolder;
+import cn.dev33.satoken.strategy.SaStrategy;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.ConfigurationProperties;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Import;
+
+/**
+ * 注册Sa-Token所需要的Bean
+ * Bean 的注册与注入应该分开在两个文件中,否则在某些场景下会造成循环依赖
+ *
+ * @author click33
+ */
+@Component
+@Import(config = {
+ SaFirewallCheckFilter.class,
+ SaTokenContextFilter.class,
+ SaTokenCorsFilter.class
+})
+public class SaBeanRegister {
+
+ public SaBeanRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = SaPathMatcherHolder::match;
+ }
+
+ /**
+ * 获取配置Bean
+ *
+ * @return 配置对象
+ */
+ @Bean
+ @ConfigurationProperties("sa-token")
+ public SaTokenConfig getSaTokenConfig() {
+ return new SaTokenConfig();
+ }
+
+ /**
+ * 应用上下文路径加载器
+ *
+ * @return /
+ */
+ @Bean
+ public ApplicationContextPathLoading getApplicationContextPathLoading() {
+ return new ApplicationContextPathLoading();
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanInject.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanInject.java
new file mode 100644
index 00000000..369b1467
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanInject.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.apiKey;
+
+import cn.dev33.satoken.apikey.SaApiKeyManager;
+import cn.dev33.satoken.apikey.config.SaApiKeyConfig;
+import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoader;
+import cn.dev33.satoken.apikey.template.SaApiKeyTemplate;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnClass;
+
+/**
+ * 注入 Sa-Token API Key 所需要的 Bean
+ *
+ * @author click33
+ * @since 1.43.0
+ */
+@Component
+@ConditionalOnClass("cn.dev33.satoken.apikey.SaApiKeyManager")
+public class SaApiKeyBeanInject {
+ /**
+ * 注入 API Key 配置对象
+ *
+ * @param saApiKeyConfig 配置对象
+ */
+ @Autowired(required = false)
+ public void setSaApiKeyConfig(SaApiKeyConfig saApiKeyConfig) {
+ SaApiKeyManager.setConfig(saApiKeyConfig);
+ }
+
+ /**
+ * 注入自定义的 API Key 模版方法 Bean
+ *
+ * @param apiKeyTemplate /
+ */
+ @Autowired(required = false)
+ public void setSaApiKeyTemplate(SaApiKeyTemplate apiKeyTemplate) {
+ SaApiKeyManager.setSaApiKeyTemplate(apiKeyTemplate);
+ }
+
+ /**
+ * 注入自定义的 API Key 数据加载器 Bean
+ *
+ * @param apiKeyDataLoader /
+ */
+ @Autowired(required = false)
+ public void setSaApiKeyDataLoader(SaApiKeyDataLoader apiKeyDataLoader) {
+ SaApiKeyManager.setSaApiKeyDataLoader(apiKeyDataLoader);
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanRegister.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanRegister.java
new file mode 100644
index 00000000..20a625f4
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/apiKey/SaApiKeyBeanRegister.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.apiKey;
+
+import cn.dev33.satoken.apikey.config.SaApiKeyConfig;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.ConfigurationProperties;
+import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnClass;
+
+/**
+ * 注册 Sa-Token API Key 所需要的 Bean
+ *
+ * @author click33
+ * @since 1.43.0
+ */
+@Component
+@ConditionalOnClass("cn.dev33.satoken.apikey.SaApiKeyManager")
+public class SaApiKeyBeanRegister {
+ /**
+ * 获取 API Key 配置对象
+ *
+ * @return 配置对象
+ */
+ @Bean
+ @ConfigurationProperties("sa-token.api-key")
+ public SaApiKeyConfig getSaApiKeyConfig() {
+ return new SaApiKeyConfig();
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/SaReactorHolder.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/SaReactorHolder.java
new file mode 100644
index 00000000..82bd87b8
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/SaReactorHolder.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.context;
+
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.fun.SaRetGenericFunction;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+import reactor.core.publisher.Mono;
+
+/**
+ * Reactor 上下文操作(异步),持有当前请求的 ServerWebExchange 全局引用
+ *
+ * @author click33
+ * @since 1.19.0
+ */
+public class SaReactorHolder {
+ public static final String REQUEST_CONTEXT_ATTRIBUTE = "com.kfyty.loveqq.framework.web.mvc.netty.request.support.RequestContextHolder.REQUEST_CONTEXT_ATTRIBUTE";
+ public static final String RESPONSE_CONTEXT_ATTRIBUTE = "com.kfyty.loveqq.framework.web.mvc.netty.request.support.ResponseContextHolder.REQUEST_CONTEXT_ATTRIBUTE";
+
+ /**
+ * 获取 Mono < ServerRequest >
+ *
+ * @return /
+ */
+ public static Mono getRequest() {
+ return Mono.deferContextual(Mono::just).map(e -> e.get(REQUEST_CONTEXT_ATTRIBUTE));
+ }
+
+ /**
+ * 获取 Mono < ServerResponse >
+ *
+ * @return /
+ */
+ public static Mono getResponse() {
+ return Mono.deferContextual(Mono::just).map(e -> e.get(RESPONSE_CONTEXT_ATTRIBUTE));
+ }
+
+ /**
+ * 将 ServerRequest/ServerResponse 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
+ *
+ * @return /
+ */
+ public static Mono sync(SaRetGenericFunction fun) {
+ return Mono.deferContextual(ctx -> {
+ SaTokenContextModelBox prev = SaTokenContextUtil.setContext(ctx.get(REQUEST_CONTEXT_ATTRIBUTE), ctx.get(RESPONSE_CONTEXT_ATTRIBUTE));
+ try {
+ return Mono.just(fun.run());
+ } finally {
+ SaTokenContextUtil.clearContext(prev);
+ }
+ });
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/path/ApplicationContextPathLoading.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/path/ApplicationContextPathLoading.java
new file mode 100644
index 00000000..7d282448
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/context/path/ApplicationContextPathLoading.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.context.path;
+
+import cn.dev33.satoken.application.ApplicationInfo;
+import cn.dev33.satoken.util.SaFoxUtil;
+import com.kfyty.loveqq.framework.core.autoconfig.CommandLineRunner;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Value;
+
+/**
+ * 应用上下文路径加载器
+ *
+ * @author click33
+ * @since 1.37.0
+ */
+public class ApplicationContextPathLoading implements CommandLineRunner {
+ @Value("${k.mvc.tomcat.contextPath:}")
+ private String contextPath;
+
+ @Override
+ public void run(String... args) throws Exception {
+
+ String routePrefix = "";
+
+ if (SaFoxUtil.isNotEmpty(contextPath)) {
+ if (!contextPath.startsWith("/")) {
+ contextPath = "/" + contextPath;
+ }
+ if (contextPath.endsWith("/")) {
+ contextPath = contextPath.substring(0, contextPath.length() - 1);
+ }
+ routePrefix += contextPath;
+ }
+
+ if (SaFoxUtil.isNotEmpty(routePrefix) && !routePrefix.equals("/")) {
+ ApplicationInfo.routePrefix = routePrefix;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaFirewallCheckFilter.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaFirewallCheckFilter.java
new file mode 100644
index 00000000..304ce3e9
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaFirewallCheckFilter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.filter;
+
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.exception.BackResultException;
+import cn.dev33.satoken.exception.FirewallCheckException;
+import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.loveqq.boot.model.LoveqqSaRequest;
+import cn.dev33.satoken.loveqq.boot.model.LoveqqSaResponse;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenOperateUtil;
+import cn.dev33.satoken.strategy.SaFirewallStrategy;
+import cn.dev33.satoken.util.SaTokenConsts;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Order;
+import com.kfyty.loveqq.framework.web.core.filter.Filter;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+
+/**
+ * 防火墙校验过滤器 (基于 loveqq-framework 统一 Filter,可以统一 servlet 和 reactor 配置)
+ *
+ * @author click33
+ * @since 1.37.0
+ */
+@Component
+@Order(SaTokenConsts.FIREWALL_CHECK_FILTER_ORDER)
+public class SaFirewallCheckFilter implements Filter {
+
+ @Override
+ public Continue doFilter(ServerRequest request, ServerResponse response) {
+ LoveqqSaRequest saRequest = new LoveqqSaRequest(request);
+ LoveqqSaResponse saResponse = new LoveqqSaResponse(response);
+ SaTokenContextModelBox prev = SaTokenContextUtil.setContext(request, response);
+ try {
+ SaFirewallStrategy.instance.check.execute(saRequest, saResponse, null);
+ } catch (StopMatchException ignored) {
+ // ignored
+ } catch (BackResultException e) {
+ SaTokenOperateUtil.writeResult(response, e.getMessage());
+ return Continue.FALSE;
+ } catch (FirewallCheckException e) {
+ if (SaFirewallStrategy.instance.checkFailHandle == null) {
+ SaTokenOperateUtil.writeResult(response, e.getMessage());
+ } else {
+ SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
+ }
+ return Continue.FALSE;
+ } finally {
+ SaTokenContextUtil.clearContext(prev);
+ }
+
+ // 更多异常则不处理,交由 Web 框架处理
+
+ // 向内执行
+ return Continue.TRUE;
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaRequestFilter.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaRequestFilter.java
new file mode 100644
index 00000000..a05a2268
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaRequestFilter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.filter;
+
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.exception.BackResultException;
+import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.filter.SaFilter;
+import cn.dev33.satoken.filter.SaFilterAuthStrategy;
+import cn.dev33.satoken.filter.SaFilterErrorStrategy;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenOperateUtil;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.util.SaTokenConsts;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Order;
+import com.kfyty.loveqq.framework.web.core.filter.Filter;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 全局鉴权过滤器 (基于 loveqq-framework 统一 Filter,可以统一 servlet 和 reactor 配置)
+ *
+ * 默认优先级为 -100,尽量保证在其它过滤器之前执行
+ *
+ *
+ * @author click33
+ * @since 1.19.0
+ */
+@Order(SaTokenConsts.ASSEMBLY_ORDER)
+public class SaRequestFilter implements SaFilter, Filter {
+
+ // ------------------------ 设置此过滤器 拦截 & 放行 的路由
+
+ /**
+ * 拦截路由
+ */
+ public List includeList = new ArrayList<>();
+
+ /**
+ * 放行路由
+ */
+ public List excludeList = new ArrayList<>();
+
+ @Override
+ public SaRequestFilter addInclude(String... paths) {
+ includeList.addAll(Arrays.asList(paths));
+ return this;
+ }
+
+ @Override
+ public SaRequestFilter addExclude(String... paths) {
+ excludeList.addAll(Arrays.asList(paths));
+ return this;
+ }
+
+ @Override
+ public SaRequestFilter setIncludeList(List pathList) {
+ includeList = pathList;
+ return this;
+ }
+
+ @Override
+ public SaRequestFilter setExcludeList(List pathList) {
+ excludeList = pathList;
+ return this;
+ }
+
+
+ // ------------------------ 钩子函数
+
+ /**
+ * 认证函数:每次请求执行
+ */
+ public SaFilterAuthStrategy auth = r -> {
+ };
+
+ /**
+ * 异常处理函数:每次[认证函数]发生异常时执行此函数
+ */
+ public SaFilterErrorStrategy error = e -> {
+ throw new SaTokenException(e);
+ };
+
+ /**
+ * 前置函数:在每次[认证函数]之前执行
+ * 注意点:前置认证函数将不受 includeList 与 excludeList 的限制,所有路由的请求都会进入 beforeAuth
+ */
+ public SaFilterAuthStrategy beforeAuth = r -> {
+ };
+
+ @Override
+ public SaRequestFilter setAuth(SaFilterAuthStrategy auth) {
+ this.auth = auth;
+ return this;
+ }
+
+ @Override
+ public SaRequestFilter setError(SaFilterErrorStrategy error) {
+ this.error = error;
+ return this;
+ }
+
+ @Override
+ public SaRequestFilter setBeforeAuth(SaFilterAuthStrategy beforeAuth) {
+ this.beforeAuth = beforeAuth;
+ return this;
+ }
+
+
+ // ------------------------ doFilter
+
+ @Override
+ public Continue doFilter(ServerRequest request, ServerResponse response) {
+ SaTokenContextModelBox prev = SaTokenContextUtil.setContext(request, response);
+ try {
+ beforeAuth.run(null);
+ SaRouter.match(includeList).notMatch(excludeList).check(r -> auth.run(null));
+ } catch (StopMatchException ignored) {
+ // ignored
+ } catch (BackResultException e) {
+ SaTokenOperateUtil.writeResult(response, e.getMessage());
+ return Continue.FALSE;
+ } catch (Throwable e) {
+ SaTokenOperateUtil.writeResult(response, String.valueOf(error.run(e)));
+ return Continue.FALSE;
+ } finally {
+ SaTokenContextUtil.clearContext(prev);
+ }
+
+ // 执行
+ return Continue.TRUE;
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenContextFilter.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenContextFilter.java
new file mode 100644
index 00000000..ba38d368
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenContextFilter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.filter;
+
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import cn.dev33.satoken.util.SaTokenConsts;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Order;
+import com.kfyty.loveqq.framework.web.core.filter.Filter;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+
+/**
+ * SaTokenContext 上下文初始化过滤器 (基于 loveqq-framework 统一 Filter,可以统一 servlet 和 reactor 配置)
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+@Component
+@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+public class SaTokenContextFilter implements Filter {
+
+ @Override
+ public Continue doFilter(ServerRequest request, ServerResponse response) {
+ SaTokenContextModelBox prev = SaTokenContextUtil.setContext(request, response);
+ return Continue.ofTrue(() -> SaTokenContextUtil.clearContext(prev));
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenCorsFilter.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenCorsFilter.java
new file mode 100644
index 00000000..9dac1807
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/filter/SaTokenCorsFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.filter;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.exception.BackResultException;
+import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenOperateUtil;
+import cn.dev33.satoken.strategy.SaStrategy;
+import cn.dev33.satoken.util.SaTokenConsts;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
+import com.kfyty.loveqq.framework.core.autoconfig.annotation.Order;
+import com.kfyty.loveqq.framework.web.core.filter.Filter;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+
+/**
+ * CORS 跨域策略过滤器 (基于 loveqq-framework 统一 Filter,可以统一 servlet 和 reactor 配置)
+ * loveqq-framework 也有跨域过滤器,切勿同时配置
+ *
+ * @author click33
+ * @see com.kfyty.loveqq.framework.web.core.cors.CorsFilter
+ * @since 1.42.0
+ */
+@Component
+@Order(SaTokenConsts.CORS_FILTER_ORDER)
+public class SaTokenCorsFilter implements Filter {
+
+ @Override
+ public Continue doFilter(ServerRequest request, ServerResponse response) {
+ SaTokenContextModelBox prev = SaTokenContextUtil.setContext(request, response);
+ try {
+ SaTokenContextModelBox box = SaHolder.getContext().getModelBox();
+ SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage());
+ } catch (StopMatchException ignored) {
+ // ignored
+ } catch (BackResultException e) {
+ SaTokenOperateUtil.writeResult(response, e.getMessage());
+ return Continue.FALSE;
+ } finally {
+ SaTokenContextUtil.clearContext(prev);
+ }
+ return Continue.TRUE;
+ }
+}
diff --git a/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/interceptor/SaInterceptor.java
new file mode 100644
index 00000000..390840fd
--- /dev/null
+++ b/sa-token-starter/sa-token-loveqq-boot-starter/src/main/java/cn/dev33/satoken/loveqq/boot/interceptor/SaInterceptor.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.loveqq.boot.interceptor;
+
+import cn.dev33.satoken.context.model.SaTokenContextModelBox;
+import cn.dev33.satoken.exception.BackResultException;
+import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.fun.SaParamFunction;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenContextUtil;
+import cn.dev33.satoken.loveqq.boot.utils.SaTokenOperateUtil;
+import cn.dev33.satoken.strategy.SaAnnotationStrategy;
+import com.kfyty.loveqq.framework.web.core.http.ServerRequest;
+import com.kfyty.loveqq.framework.web.core.http.ServerResponse;
+import com.kfyty.loveqq.framework.web.core.interceptor.HandlerInterceptor;
+import com.kfyty.loveqq.framework.web.core.mapping.MethodMapping;
+
+import java.lang.reflect.Method;
+
+/**
+ * Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力
+ *
+ * @author click33
+ * @since 1.31.0
+ */
+public class SaInterceptor implements HandlerInterceptor {
+ /**
+ * 是否打开注解鉴权,配置为 true 时注解鉴权才会生效,配置为 false 时,即使写了注解也不会进行鉴权
+ */
+ public boolean isAnnotation = true;
+
+ /**
+ * 认证前置函数:在注解鉴权之前执行
+ * 参数:路由处理函数指针
+ */
+ public SaParamFunction