mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-05-14 12:52:08 +08:00
refactor: 重构所有 starter 组件的 SaTokenContext 上下文读写策略
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- spring-web (optional) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -31,11 +31,10 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- reactor-core (optional) -->
|
||||
<!-- reactor-core -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- jackson-databind (optional) -->
|
||||
@@ -51,36 +50,25 @@
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token-core -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- sa-token-spring-boot-autoconfig -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-autoconfig</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency> -->
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>5.3.7</version>
|
||||
<version>5.3.39</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package cn.dev33.satoken.reactor.context;
|
||||
|
||||
import cn.dev33.satoken.fun.SaRetGenericFunction;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
/**
|
||||
* Reactor 上下文操作(异步),持有当前请求的 ServerWebExchange 全局引用
|
||||
@@ -28,37 +31,67 @@ import reactor.core.publisher.Mono;
|
||||
public class SaReactorHolder {
|
||||
|
||||
/**
|
||||
* key
|
||||
* ServerWebExchange key
|
||||
*/
|
||||
public static final Class<ServerWebExchange> CONTEXT_KEY = ServerWebExchange.class;
|
||||
public static final String EXCHANGE_KEY = "SA_REACTOR_EXCHANGE_KEY";
|
||||
|
||||
/**
|
||||
* chain_key
|
||||
* WebFilterChain key
|
||||
*/
|
||||
public static final String CHAIN_KEY = "WEB_FILTER_CHAIN_KEY";
|
||||
|
||||
public static final String CHAIN_KEY = "SA_REACTOR__CHAIN_KEY";
|
||||
|
||||
/**
|
||||
* 获取上下文对象
|
||||
* @return see note
|
||||
* 在流式上下文写入 ServerWebExchange
|
||||
* @param ctx 必填
|
||||
* @param exchange 必填
|
||||
* @param chain 非必填
|
||||
* @return /
|
||||
*/
|
||||
public static Mono<ServerWebExchange> getContext() {
|
||||
// 从全局 Mono<Context> 获取
|
||||
return Mono.subscriberContext().map(ctx -> ctx.get(CONTEXT_KEY));
|
||||
public static Context setContext(Context ctx, ServerWebExchange exchange, WebFilterChain chain) {
|
||||
return ctx
|
||||
.put(EXCHANGE_KEY, exchange)
|
||||
.put(CHAIN_KEY, chain);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上下文对象, 并设置到同步上下文中
|
||||
* @return see note
|
||||
* 在流式上下文获取 ServerWebExchange
|
||||
* @param ctx /
|
||||
* @return /
|
||||
*/
|
||||
public static Mono<ServerWebExchange> getContextAndSetSync() {
|
||||
// 从全局 Mono<Context> 获取
|
||||
return Mono.subscriberContext().map(ctx -> {
|
||||
// 设置到sync中
|
||||
SaReactorSyncHolder.setContext(ctx.get(CONTEXT_KEY));
|
||||
return ctx.get(CONTEXT_KEY);
|
||||
}).doFinally(r->{
|
||||
// 从sync中清除
|
||||
SaReactorSyncHolder.clearContext();
|
||||
public static ServerWebExchange getExchange(ContextView ctx) {
|
||||
return ctx.get(EXCHANGE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在流式上下文获取 WebFilterChain
|
||||
* @param ctx /
|
||||
* @return /
|
||||
*/
|
||||
public static WebFilterChain getChain(ContextView ctx) {
|
||||
return ctx.get(CHAIN_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Mono < ServerWebExchange >
|
||||
* @return /
|
||||
*/
|
||||
public static Mono<ServerWebExchange> getMonoExchange() {
|
||||
return Mono.deferContextual(ctx -> Mono.just(getExchange(ctx)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public static <R> Mono<R> sync(SaRetGenericFunction<R> fun) {
|
||||
return Mono.deferContextual(ctx -> {
|
||||
try {
|
||||
SaReactorSyncHolder.setContext(ctx.get(EXCHANGE_KEY));
|
||||
return Mono.just(fun.run());
|
||||
} finally {
|
||||
SaReactorSyncHolder.clearContext();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
package cn.dev33.satoken.reactor.context;
|
||||
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
|
||||
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.fun.SaRetGenericFunction;
|
||||
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
|
||||
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
|
||||
import cn.dev33.satoken.reactor.model.SaStorageForReactor;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Reactor上下文操作(同步),持有当前请求的 ServerWebExchange 全局引用
|
||||
@@ -36,8 +35,8 @@ import cn.dev33.satoken.reactor.model.SaStorageForReactor;
|
||||
public class SaReactorSyncHolder {
|
||||
|
||||
/**
|
||||
* 写入上下文对象
|
||||
* @param exchange see note
|
||||
* 在同步上下文写入 ServerWebExchange
|
||||
* @param exchange /
|
||||
*/
|
||||
public static void setContext(ServerWebExchange exchange) {
|
||||
SaRequest request = new SaRequestForReactor(exchange.getRequest());
|
||||
@@ -45,32 +44,32 @@ public class SaReactorSyncHolder {
|
||||
SaStorage storage = new SaStorageForReactor(exchange);
|
||||
SaTokenContextForThreadLocalStorage.setBox(request, response, storage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上下文对象
|
||||
* @return see note
|
||||
*/
|
||||
public static ServerWebExchange getContext() {
|
||||
Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
|
||||
return (ServerWebExchange)box.getStorage().getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除上下文对象
|
||||
* 在同步上下文清除 ServerWebExchange
|
||||
*/
|
||||
public static void clearContext() {
|
||||
SaTokenContextForThreadLocalStorage.clearBox();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 写入上下文对象, 并在执行函数后将其清除
|
||||
* @param exchange see note
|
||||
* @param fun see note
|
||||
* 在同步上下文获取 ServerWebExchange
|
||||
* @return /
|
||||
*/
|
||||
public static void setContext(ServerWebExchange exchange, SaFunction fun) {
|
||||
public static ServerWebExchange getExchange() {
|
||||
Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
|
||||
return (ServerWebExchange)box.getStorage().getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
|
||||
* @param exchange /
|
||||
* @param fun /
|
||||
*/
|
||||
public static <R>R setContext(ServerWebExchange exchange, SaRetGenericFunction<R> fun) {
|
||||
try {
|
||||
setContext(exchange);
|
||||
fun.run();
|
||||
return fun.run();
|
||||
} finally {
|
||||
clearContext();
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.error;
|
||||
|
||||
/**
|
||||
* 定义 sa-token-reactor-spring-boot-starter 所有异常细分状态码
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.33.0
|
||||
*/
|
||||
public interface SaReactorSpringBootErrorCode {
|
||||
|
||||
/** 对象转 JSON 字符串失败 */
|
||||
int CODE_20203 = 20203;
|
||||
|
||||
/** JSON 字符串转 Map 失败 */
|
||||
int CODE_20204 = 20204;
|
||||
|
||||
/** 默认的 Filter 异常处理函数 */
|
||||
int CODE_20205 = 20205;
|
||||
|
||||
}
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package cn.dev33.satoken.reactor.filter;
|
||||
|
||||
import cn.dev33.satoken.exception.BackResultException;
|
||||
import cn.dev33.satoken.exception.FirewallCheckException;
|
||||
import cn.dev33.satoken.exception.StopMatchException;
|
||||
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
|
||||
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
|
||||
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
|
||||
import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
|
||||
import cn.dev33.satoken.strategy.SaFirewallStrategy;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -43,21 +46,25 @@ public class SaFirewallCheckFilterForReactor implements WebFilter {
|
||||
SaResponseForReactor saResponse = new SaResponseForReactor(exchange.getResponse());
|
||||
|
||||
try {
|
||||
SaReactorSyncHolder.setContext(exchange);
|
||||
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, exchange);
|
||||
}
|
||||
catch (StopMatchException e) {
|
||||
// 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
|
||||
catch (StopMatchException ignored) {}
|
||||
catch (BackResultException e) {
|
||||
return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
|
||||
}
|
||||
// FirewallCheckException 异常则交由异常处理策略处理
|
||||
catch (FirewallCheckException e) {
|
||||
// FirewallCheckException 异常则交由异常处理策略处理
|
||||
if(SaFirewallStrategy.instance.checkFailHandle == null) {
|
||||
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
|
||||
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(e.getMessage().getBytes())));
|
||||
return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
|
||||
} else {
|
||||
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
SaReactorSyncHolder.clearContext();
|
||||
}
|
||||
// 更多异常则不处理,交由 Web 框架处理
|
||||
|
||||
// 向下执行
|
||||
|
||||
@@ -21,9 +21,8 @@ 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.reactor.context.SaReactorHolder;
|
||||
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
|
||||
import cn.dev33.satoken.reactor.error.SaReactorSpringBootErrorCode;
|
||||
import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -37,7 +36,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reactor 全局鉴权过滤器
|
||||
* 全局鉴权过滤器 (基于 Reactor)
|
||||
* <p>
|
||||
* 默认优先级为 -100,尽量保证在其它过滤器之前执行
|
||||
* </p>
|
||||
@@ -103,7 +102,7 @@ public class SaReactorFilter implements SaFilter, WebFilter {
|
||||
* 异常处理函数:每次[认证函数]发生异常时执行此函数
|
||||
*/
|
||||
public SaFilterErrorStrategy error = e -> {
|
||||
throw new SaTokenException(e).setCode(SaReactorSpringBootErrorCode.CODE_20205);
|
||||
throw new SaTokenException(e);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -135,55 +134,25 @@ public class SaReactorFilter implements SaFilter, WebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
|
||||
// 写入WebFilterChain对象
|
||||
exchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);
|
||||
|
||||
|
||||
// ---------- 全局认证处理
|
||||
try {
|
||||
// 写入全局上下文 (同步)
|
||||
SaReactorSyncHolder.setContext(exchange);
|
||||
|
||||
// 执行全局过滤器
|
||||
beforeAuth.run(null);
|
||||
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
|
||||
auth.run(null);
|
||||
});
|
||||
|
||||
} catch (StopMatchException e) {
|
||||
// StopMatchException 异常代表:停止匹配,进入Controller
|
||||
|
||||
} catch (Throwable e) {
|
||||
// 1. 获取异常处理策略结果
|
||||
String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
|
||||
|
||||
// 2. 写入输出流
|
||||
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
|
||||
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
|
||||
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
|
||||
}
|
||||
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
|
||||
|
||||
} finally {
|
||||
// 清除上下文
|
||||
SaRouter.match(includeList).notMatch(excludeList).check(r -> auth.run(null));
|
||||
}
|
||||
catch (StopMatchException ignored) {}
|
||||
catch (BackResultException e) {
|
||||
return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return SaReactorOperateUtil.writeResult(exchange, String.valueOf(error.run(e)));
|
||||
}
|
||||
finally {
|
||||
SaReactorSyncHolder.clearContext();
|
||||
}
|
||||
|
||||
// ---------- 执行
|
||||
|
||||
// 写入全局上下文 (同步)
|
||||
SaReactorSyncHolder.setContext(exchange);
|
||||
|
||||
// 执行
|
||||
return chain.filter(exchange).subscriberContext(ctx -> {
|
||||
// 写入全局上下文 (异步)
|
||||
ctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);
|
||||
return ctx;
|
||||
}).doFinally(r -> {
|
||||
// 清除上下文
|
||||
SaReactorSyncHolder.clearContext();
|
||||
});
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.reactor.context.SaReactorHolder;
|
||||
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;
|
||||
|
||||
/**
|
||||
* SaTokenContext 上下文初始化过滤器 (基于 Reactor)
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.42.0
|
||||
*/
|
||||
@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
|
||||
public class SaTokenContextFilterForReactor implements WebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
return chain.filter(exchange)
|
||||
.contextWrite(ctx -> SaReactorHolder.setContext(ctx, exchange, chain))
|
||||
.doFinally(r -> {
|
||||
// 在流式上下文中保存的数据会随着流式操作的结束而销毁,所以此处无需手动清除数据
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 这种写法有问题:
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
try {
|
||||
SaReactorSyncHolder.setContext(exchange);
|
||||
return chain.filter(exchange);
|
||||
} finally {
|
||||
SaReactorSyncHolder.clearContext();
|
||||
}
|
||||
}
|
||||
这种写法会先执行 finally,然后进入具体的 Controller
|
||||
*/
|
||||
@@ -184,7 +184,7 @@ public class SaRequestForReactor implements SaRequest {
|
||||
*/
|
||||
@Override
|
||||
public Object forward(String path) {
|
||||
ServerWebExchange exchange = SaReactorSyncHolder.getContext();
|
||||
ServerWebExchange exchange = SaReactorSyncHolder.getExchange();
|
||||
WebFilterChain chain = exchange.getAttribute(SaReactorHolder.CHAIN_KEY);
|
||||
|
||||
ServerHttpRequest newRequest = request.mutate().path(path).build();
|
||||
|
||||
@@ -16,22 +16,15 @@
|
||||
package cn.dev33.satoken.reactor.spring;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
|
||||
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
|
||||
|
||||
/**
|
||||
* <h2> 此为低版本(<1.42.0) 的上下文处理方案,仅做留档,如无必要请勿使用 </h2>
|
||||
*
|
||||
* Sa-Token 上下文处理器 [ Spring Reactor 版本实现 ] ,基于 SaTokenContextForThreadLocal 定制
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.33.0
|
||||
*/
|
||||
public class SaTokenContextForSpringReactor extends SaTokenContextForThreadLocal {
|
||||
|
||||
/**
|
||||
* 重写路由匹配方法
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
return SaPathPatternParserUtil.match(pattern, path);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
package cn.dev33.satoken.reactor.spring;
|
||||
|
||||
import cn.dev33.satoken.reactor.filter.SaFirewallCheckFilterForReactor;
|
||||
import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor;
|
||||
import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
|
||||
import cn.dev33.satoken.strategy.SaStrategy;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContext;
|
||||
|
||||
/**
|
||||
* 注册 Sa-Token 所需要的 Bean
|
||||
*
|
||||
@@ -28,18 +29,25 @@ import cn.dev33.satoken.context.SaTokenContext;
|
||||
*/
|
||||
public class SaTokenContextRegister {
|
||||
|
||||
/**
|
||||
* 获取上下文处理器组件 (Spring Reactor 版)
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@Bean
|
||||
public SaTokenContext getSaTokenContextForSpringReactor() {
|
||||
return new SaTokenContextForSpringReactor();
|
||||
public SaTokenContextRegister() {
|
||||
// 重写路由匹配算法
|
||||
SaStrategy.instance.routeMatcher = (pattern, path) -> {
|
||||
return SaPathPatternParserUtil.match(pattern, path);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求 path 校验过滤器
|
||||
* 上下文过滤器
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@Bean
|
||||
public SaTokenContextFilterForReactor saTokenContextFilterForServlet() {
|
||||
return new SaTokenContextFilterForReactor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 防火墙过滤器
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import org.springframework.boot.SpringBootVersion;
|
||||
|
||||
/**
|
||||
* SpringBoot 版本与 Sa-Token 版本兼容检查器
|
||||
* SpringBoot 版本与 Sa-Token 版本兼容检查器,当开发者错误的在 SpringBoot3.x 项目中引入当前集成包时,将在控制台做出提醒并阻断项目启动
|
||||
*
|
||||
* @author Uncarbon
|
||||
* @since 1.38.0
|
||||
@@ -22,4 +22,5 @@ public class SpringBootVersionCompatibilityChecker {
|
||||
System.err.println(str);
|
||||
throw new SaTokenException(str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Reactor 操作工具类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.42.0
|
||||
*/
|
||||
public class SaReactorOperateUtil {
|
||||
|
||||
/**
|
||||
* 写入结果到输出流
|
||||
* @param exchange /
|
||||
* @param result /
|
||||
* @return /
|
||||
*/
|
||||
public static Mono<Void> writeResult(ServerWebExchange exchange, String result) {
|
||||
// 写入输出流
|
||||
// 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
|
||||
// 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
|
||||
exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
|
||||
}
|
||||
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user