diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCorsHandleFunction.java b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCorsHandleFunction.java new file mode 100644 index 00000000..536b2136 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCorsHandleFunction.java @@ -0,0 +1,44 @@ +/* + * 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.fun.strategy; + +import cn.dev33.satoken.context.model.SaRequest; +import cn.dev33.satoken.context.model.SaResponse; +import cn.dev33.satoken.context.model.SaStorage; + +/** + * CORS 跨域策略处理函数 + * + * @author click33 + * @since 1.42.0 + */ +@FunctionalInterface +public interface SaCorsHandleFunction { + + /** + * CORS 策略处理函数 + * + * @param req 请求包装对象 + * @param res 响应包装对象 + * @param sto 数据读写对象 + */ + void execute( + SaRequest req, + SaResponse res, + SaStorage sto + ); + +} \ No newline at end of file diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java index 09726fbc..6a18c519 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java @@ -184,6 +184,13 @@ public final class SaStrategy { throw new NotImplException("未实现具体路由匹配策略").setCode(SaErrorCode.CODE_12401); }; + /** + * CORS 策略处理函数 + */ + public SaCorsHandleFunction corsHandle = (req, res, sto) -> { + + }; + // ----------------------- 重写策略 set连缀风格 diff --git a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaTokenConfigure.java index 1b8be8e0..1f249931 100644 --- a/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -2,7 +2,9 @@ package com.pj.satoken; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction; import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaHttpMethod; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.strategy.SaAnnotationStrategy; @@ -110,8 +112,31 @@ public class SaTokenConfigure implements WebMvcConfigurer { }) ; } - - /** + + /** + * CORS 跨域处理 + */ + @Bean + public SaCorsHandleFunction corsHandle() { + return (req, res, sto) -> { + res. + // 允许指定域访问跨域资源 + setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "*"); + + // 如果是预检请求,则立即返回到前端 + SaRouter.match(SaHttpMethod.OPTIONS) + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + .back(); + }; + } + + /** * 重写 Sa-Token 框架内部算法策略 */ @PostConstruct diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/SSOController.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/SSOController.java deleted file mode 100644 index 8cc55287..00000000 --- a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/test/SSOController.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.pj.test; - -import org.noear.solon.annotation.Controller; -import org.noear.solon.annotation.Mapping; - -import com.pj.util.AjaxJson; - -import cn.dev33.satoken.stp.StpUtil; -import org.noear.solon.annotation.Param; - -/** - * 测试: 同域单点登录 - * @author click33 - * @author noear - */ -@Controller -@Mapping("/sso/") -public class SSOController { - - // 测试:进行登录 - @Mapping("doLogin") - public AjaxJson doLogin(@Param(defaultValue = "10001") String id) { - System.out.println("---------------- 进行登录 "); - StpUtil.login(id); - return AjaxJson.getSuccess("登录成功: " + id); - } - - // 测试:是否登录 - @Mapping("isLogin") - public AjaxJson isLogin() { - System.out.println("---------------- 是否登录 "); - boolean isLogin = StpUtil.isLogin(); - return AjaxJson.getSuccess("是否登录: " + isLogin); - } - -} diff --git a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java index 04a13690..4173e403 100644 --- a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -2,6 +2,7 @@ package com.pj.satoken; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.plugin.SaTokenPluginHolder; import cn.dev33.satoken.router.SaHttpMethod; @@ -14,79 +15,88 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** - * [Sa-Token 权限认证] 配置类 + * [Sa-Token 权限认证] 配置类 * @author click33 * */ @Configuration public class SaTokenConfigure implements WebMvcConfigurer { - + /** - * 注册 Sa-Token 拦截器打开注解鉴权功能 + * 注册 Sa-Token 拦截器打开注解鉴权功能 */ @Override public void addInterceptors(InterceptorRegistry registry) { - // 注册 Sa-Token 拦截器打开注解鉴权功能 + // 注册 Sa-Token 拦截器打开注解鉴权功能 registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } - + /** - * 注册 [Sa-Token 全局过滤器] + * 注册 [Sa-Token 全局过滤器] */ @Bean public SaServletFilter getSaServletFilter() { return new SaServletFilter() - + // 指定 [拦截路由] 与 [放行路由] .addInclude("/**")// .addExclude("/favicon.ico") - - // 认证函数: 每次请求执行 + + // 认证函数: 每次请求执行 .setAuth(obj -> { - // 输出 API 请求日志,方便调试代码 + // 输出 API 请求日志,方便调试代码 // SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue()); - + }) - - // 异常处理函数:每次认证函数发生异常时执行此函数 + + // 异常处理函数:每次认证函数发生异常时执行此函数 .setError(e -> { System.out.println("---------- sa全局异常 "); e.printStackTrace(); return SaResult.error(e.getMessage()); }) - + // 前置函数:在每次认证函数之前执行 .setBeforeAuth(obj -> { // ---------- 设置一些安全响应头 ---------- SaHolder.getResponse() - // 服务器名称 + // 服务器名称 .setServer("sa-server") - // 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以 + // 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以 .setHeader("X-Frame-Options", "SAMEORIGIN") // 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面 .setHeader("X-XSS-Protection", "1; mode=block") - // 禁用浏览器内容嗅探 + // 禁用浏览器内容嗅探 .setHeader("X-Content-Type-Options", "nosniff") - - // ---------- 设置跨域响应头 ---------- - // 允许指定域访问跨域资源 - .setHeader("Access-Control-Allow-Origin", "*") - // 允许所有请求方式 - .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") - // 有效时间 - .setHeader("Access-Control-Max-Age", "3600") - // 允许的header参数 - .setHeader("Access-Control-Allow-Headers", "*"); - - // 如果是预检请求,则立即返回到前端 - SaRouter.match(SaHttpMethod.OPTIONS) - .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) - .back(); + ; }) ; } /** - * 注册 [Sa-Token 全局过滤器] + * CORS 跨域处理 + */ + @Bean + public SaCorsHandleFunction corsHandle() { + return (req, res, sto) -> { + res. + // 允许指定域访问跨域资源 + setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "*"); + + // 如果是预检请求,则立即返回到前端 + SaRouter.match(SaHttpMethod.OPTIONS) + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + .back(); + }; + } + + /** + * 注册插件 */ @Bean public SaTokenPluginHolder getSaTokenPluginHolder() { diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.java new file mode 100644 index 00000000..65a2b985 --- /dev/null +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.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.reactor.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.reactor.context.SaReactorSyncHolder; +import cn.dev33.satoken.reactor.util.SaReactorOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import org.springframework.core.annotation.Order; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +/** + * CORS 跨域策略过滤器 (基于 Reactor) + * + * @author click33 + * @since 1.42.0 + */ +@Order(SaTokenConsts.CORS_FILTER_ORDER) +public class SaTokenCorsFilterForReactor implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + + try { + SaReactorSyncHolder.setContext(exchange); + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + return SaReactorOperateUtil.writeResult(exchange, e.getMessage()); + } + finally { + SaReactorSyncHolder.clearContext(); + } + + return chain.filter(exchange); + } + +} diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java index d5561274..559be296 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java @@ -17,6 +17,7 @@ package cn.dev33.satoken.reactor.spring; import cn.dev33.satoken.reactor.filter.SaFirewallCheckFilterForReactor; import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor; +import cn.dev33.satoken.reactor.filter.SaTokenCorsFilterForReactor; import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil; import cn.dev33.satoken.strategy.SaStrategy; import org.springframework.context.annotation.Bean; @@ -46,6 +47,16 @@ public class SaTokenContextRegister { return new SaTokenContextFilterForReactor(); } + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean + public SaTokenCorsFilterForReactor saTokenCorsFilterForReactor() { + return new SaTokenCorsFilterForReactor(); + } + /** * 防火墙过滤器 * diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.java new file mode 100644 index 00000000..65a2b985 --- /dev/null +++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenCorsFilterForReactor.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.reactor.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.reactor.context.SaReactorSyncHolder; +import cn.dev33.satoken.reactor.util.SaReactorOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import org.springframework.core.annotation.Order; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +/** + * CORS 跨域策略过滤器 (基于 Reactor) + * + * @author click33 + * @since 1.42.0 + */ +@Order(SaTokenConsts.CORS_FILTER_ORDER) +public class SaTokenCorsFilterForReactor implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + + try { + SaReactorSyncHolder.setContext(exchange); + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + return SaReactorOperateUtil.writeResult(exchange, e.getMessage()); + } + finally { + SaReactorSyncHolder.clearContext(); + } + + return chain.filter(exchange); + } + +} diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java index d5561274..559be296 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java +++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java @@ -17,6 +17,7 @@ package cn.dev33.satoken.reactor.spring; import cn.dev33.satoken.reactor.filter.SaFirewallCheckFilterForReactor; import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor; +import cn.dev33.satoken.reactor.filter.SaTokenCorsFilterForReactor; import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil; import cn.dev33.satoken.strategy.SaStrategy; import org.springframework.context.annotation.Bean; @@ -46,6 +47,16 @@ public class SaTokenContextRegister { return new SaTokenContextFilterForReactor(); } + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean + public SaTokenCorsFilterForReactor saTokenCorsFilterForReactor() { + return new SaTokenCorsFilterForReactor(); + } + /** * 防火墙过滤器 * diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanInject.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanInject.java index f50b10e7..2e8c94db 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanInject.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanInject.java @@ -22,6 +22,7 @@ import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoader; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction; import cn.dev33.satoken.httpauth.basic.SaHttpBasicTemplate; import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.httpauth.digest.SaHttpDigestTemplate; @@ -41,6 +42,7 @@ import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.strategy.SaAnnotationStrategy; import cn.dev33.satoken.strategy.SaFirewallStrategy; +import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.strategy.hooks.SaFirewallCheckHook; import cn.dev33.satoken.temp.SaTempTemplate; import org.noear.solon.annotation.Bean; @@ -275,6 +277,17 @@ public class SaBeanInject { } } + /** + * 注入CORS 策略处理函数 + * + * @param corsHandle / + */ + @Condition(onBean = SaCorsHandleFunction.class) + @Bean + public void setCorsHandle(SaCorsHandleFunction corsHandle) { + SaStrategy.instance.corsHandle = corsHandle; + } + /** * 注入自定义插件集合 * diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java index 0738e9e7..be4aa73f 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java @@ -18,6 +18,7 @@ package cn.dev33.satoken.solon; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.solon.integration.SaFirewallCheckFilterForSolon; import cn.dev33.satoken.solon.integration.SaTokenContextFilterForSolon; +import cn.dev33.satoken.solon.integration.SaTokenCorsFilterForSolon; import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaTokenConsts; import org.noear.solon.annotation.Bean; @@ -66,6 +67,16 @@ public class SaBeanRegister { return new SaTokenContextFilterForSolon(); } + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean(index = SaTokenConsts.CORS_FILTER_ORDER) + public Filter saTokenCorsFilterForSolon() { + return new SaTokenCorsFilterForSolon(); + } + /** * 防火墙过滤器 * diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenCorsFilterForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenCorsFilterForSolon.java new file mode 100644 index 00000000..8f68dd60 --- /dev/null +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenCorsFilterForSolon.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.solon.integration; + +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.solon.util.SaSolonOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Filter; +import org.noear.solon.core.handle.FilterChain; + +/** + * CORS 跨域策略过滤器 (基于 Solon) + * + * @author click33 + * @since 1.42.0 + */ +public class SaTokenCorsFilterForSolon implements Filter { + + @Override + public void doFilter(Context ctx, FilterChain chain) throws Throwable { + + try { + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + SaSolonOperateUtil.writeResult(ctx, e.getMessage()); + return; + } + + chain.doFilter(ctx); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java index ad22ff6c..8a055cf0 100644 --- a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java +++ b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanInject.java @@ -22,6 +22,7 @@ import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoader; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction; import cn.dev33.satoken.httpauth.basic.SaHttpBasicTemplate; import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.httpauth.digest.SaHttpDigestTemplate; @@ -42,6 +43,7 @@ import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.strategy.SaAnnotationStrategy; import cn.dev33.satoken.strategy.SaFirewallStrategy; +import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.strategy.hooks.SaFirewallCheckHook; import cn.dev33.satoken.temp.SaTempTemplate; import org.springframework.beans.factory.annotation.Autowired; @@ -268,6 +270,16 @@ public class SaBeanInject { } } + /** + * 注入CORS 策略处理函数 + * + * @param corsHandle / + */ + @Autowired(required = false) + public void setCorsHandle(SaCorsHandleFunction corsHandle) { + SaStrategy.instance.corsHandle = corsHandle; + } + /** * 注入自定义插件集合 * diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForServlet.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForServlet.java new file mode 100644 index 00000000..04a4e7ab --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForServlet.java @@ -0,0 +1,55 @@ +/* + * 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.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.servlet.util.SaServletOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import org.springframework.core.annotation.Order; + +import javax.servlet.*; +import java.io.IOException; + +/** + * CORS 跨域策略过滤器 (基于 Servlet) + * + * @author click33 + * @since 1.42.0 + */ +@Order(SaTokenConsts.CORS_FILTER_ORDER) +public class SaTokenCorsFilterForServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + try { + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + SaServletOperateUtil.writeResult(response, e.getMessage()); + return; + } + + chain.doFilter(request, response); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java index 4f53b570..9eda9a83 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java @@ -17,6 +17,7 @@ package cn.dev33.satoken.spring; import cn.dev33.satoken.filter.SaFirewallCheckFilterForServlet; import cn.dev33.satoken.filter.SaTokenContextFilterForServlet; +import cn.dev33.satoken.filter.SaTokenCorsFilterForServlet; import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder; import cn.dev33.satoken.strategy.SaStrategy; import org.springframework.context.annotation.Bean; @@ -46,6 +47,16 @@ public class SaTokenContextRegister { return new SaTokenContextFilterForServlet(); } + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean + public SaTokenCorsFilterForServlet saTokenCorsFilterForServlet() { + return new SaTokenCorsFilterForServlet(); + } + /** * 防火墙过滤器 * diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java new file mode 100644 index 00000000..f0c04a99 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java @@ -0,0 +1,55 @@ +/* + * 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.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.servlet.util.SaJakartaServletOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import jakarta.servlet.*; +import org.springframework.core.annotation.Order; + +import java.io.IOException; + +/** + * CORS 跨域策略过滤器 (基于 Jakarta-Servlet) + * + * @author click33 + * @since 1.42.0 + */ +@Order(SaTokenConsts.CORS_FILTER_ORDER) +public class SaTokenCorsFilterForJakartaServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + try { + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + SaJakartaServletOperateUtil.writeResult(response, e.getMessage()); + return; + } + + chain.doFilter(request, response); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java index 48cc43d9..4792da2d 100644 --- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java +++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java @@ -17,6 +17,7 @@ package cn.dev33.satoken.spring; import cn.dev33.satoken.filter.SaFirewallCheckFilterForJakartaServlet; import cn.dev33.satoken.filter.SaTokenContextFilterForJakartaServlet; +import cn.dev33.satoken.filter.SaTokenCorsFilterForJakartaServlet; import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil; import cn.dev33.satoken.strategy.SaStrategy; import org.springframework.context.annotation.Bean; @@ -46,6 +47,16 @@ public class SaTokenContextRegister { return new SaTokenContextFilterForJakartaServlet(); } + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean + public SaTokenCorsFilterForJakartaServlet saTokenCorsFilterForJakartaServlet() { + return new SaTokenCorsFilterForJakartaServlet(); + } + /** * 防火墙过滤器 *