gpt4 book ai didi

Spring WebFlux、安全和请求体

转载 作者:行者123 更新时间:2023-12-04 17:19:55 24 4
gpt4 key购买 nike

我需要使用请求主体的 HMAC 来保护通过 Spring Boot、WebFlux 和 spring security 实现的 REST API。稍微简化一下,在较高层次上 - 请求带有具有请求正文哈希值的 header ,因此我必须读取 header 、读取正文、计算正文的哈希值并与 header 值进行比较。

我认为我应该实现 ServerAuthenticationConverter 但到目前为止我能找到的所有示例都只查看请求 header ,而不是请求正文,我不确定我是否可以只阅读正文,或者我应该用缓存的主体包装/改变请求,以便它可以被底层组件第二次使用?

是否可以按照以下方式使用:

public class HttpHmacAuthenticationConverter implements ServerAuthenticationConverter {

@Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
exchange.getRequest().getBody()
.next()
.flatMap(dataBuffer -> {
try {
return Mono.just(StreamUtils.copyToString(dataBuffer.asInputStream(), StandardCharsets.UTF_8));
} catch (IOException e) {
return Mono.error(e);
}
})
...


我在 copyToString 行收到来自 IDE 的警告:Inappropriate blocking method call

有任何指南或示例吗?

谢谢!

我也试过:

    @Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
return Mono.justOrEmpty(exchange.getRequest().getHeaders().toSingleValueMap())
.zipWith(exchange.getRequest().getBody().next()
.flatMap(dataBuffer -> Mono.just(dataBuffer.asByteBuffer().array()))
)
.flatMap(tuple -> create(tuple.getT1(), tuple.getT2()));

但这不起作用 - 最后一行的 create() 方法中的代码永远不会执行。

最佳答案

我让它工作。发布我的代码以供引用。

需要两个组件才能使其工作 - WebFilter 将读取和缓存请求主体,以便它可以被多次使用,而 ServerAuthenticationConverter 将计算主体的哈希值并验证签名。

public class HttpRequestBodyCachingFilter implements WebFilter {
private static final byte[] EMPTY_BODY = new byte[0];

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// GET and DELETE don't have a body
HttpMethod method = exchange.getRequest().getMethod();
if (method == null || method.matches(HttpMethod.GET.name()) || method.matches(HttpMethod.DELETE.name())) {
return chain.filter(exchange);
}

return DataBufferUtils.join(exchange.getRequest().getBody())
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
})
.defaultIfEmpty(EMPTY_BODY)
.flatMap(bytes -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Nonnull
@Override
public Flux<DataBuffer> getBody() {
if (bytes.length > 0) {
DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
return Flux.just(dataBufferFactory.wrap(bytes));
}
return Flux.empty();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
});
}

public class HttpJwsAuthenticationConverter implements ServerAuthenticationConverter {
private static final byte[] EMPTY_BODY = new byte[0];

@Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
return DataBufferUtils.join(exchange.getRequest().getBody())
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
})
.defaultIfEmpty(EMPTY_BODY)
.flatMap(body -> create(
exchange.getRequest().getMethod(),
getFullRequestPath(exchange.getRequest()),
exchange.getRequest().getHeaders(),
body)
);
}

...

Converter 中的create 方法实现了根据请求方法、路径、 header 和正文验证签名的逻辑。如果成功则返回 Authentication 的实例,否则返回 Mono.empty()

接线是这样完成的:

public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange().pathMatchers(PATH_API).authenticated()
...
.and()
.addFilterBefore(new HttpRequestBodyCachingFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
.addFilterAt(jwtAuthenticationFilter(...), SecurityWebFiltersOrder.AUTHENTICATION);
}

private AuthenticationWebFilter jwtAuthenticationFilter(ReactiveAuthenticationManager authManager) {
AuthenticationWebFilter authFilter = new AuthenticationWebFilter(authManager);
authFilter.setServerAuthenticationConverter(new HttpJwsAuthenticationConverter());
authFilter.setRequiresAuthenticationMatcher(ServerWebExchangeMatchers.pathMatchers(PATH_API));
return authFilter;
}

@Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager() {
return Mono::just;
}


}

关于Spring WebFlux、安全和请求体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66822340/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com