我正在尝试拦截所有请求,以便对身体进行消毒。我已经创建了一个过滤器来实现这一点,但这不起作用,因为Micronaut已经使用JsonContentProcessor序列化了请求
我的过滤器:
@Filter("/**")
public class RequestSanitizationFilter implements HttpServerFilter {
private static final String SPECIAL_CHARACTERS = "()[]{}\%/<>?$";
@Override
public int getOrder() {
return ServerFilterPhase.FIRST.order();
}
@Override
public Publisher<MutableHttpResponse<?>> doFilter(
HttpRequest<?> request, ServerFilterChain chain) {
String finalBody = request.getBody().toString();
for (char i : SPECIAL_CHARACTERS.toCharArray()) {
finalBody = finalBody.replace("" + i, "");
}
return Single.fromPublisher(chain.proceed(request.mutate().body(finalBody))).toFlowable();
}
}
我找不到任何本土的东西可以帮助我。在进入控制器之前,有其他方法可以做到这一点吗?
由于Micronaut是在Netty上构建的,读取主体是根据控制器的绑定要求以非阻塞方式使用异步I/O完成的,控制器的绑定需求可以根据不同的方法进行更改。因此,不可能知道或以不阻止从过滤器读取正文的方式进行读取。
如果你想验证主体,你可以使用Netty通道处理程序:
package request.body.test;
import java.nio.charset.StandardCharsets;
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.http.client.exceptions.HttpClientResponseException;
import io.micronaut.http.server.HttpServerConfiguration;
import io.micronaut.http.server.netty.NettyServerCustomizer;
import io.micronaut.runtime.EmbeddedApplication;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.junit.jupiter.api.Test;
import static io.micronaut.http.netty.channel.ChannelPipelineCustomizer.HANDLER_HTTP_STREAM;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@MicronautTest
class RequestBodyTest {
@Inject
EmbeddedApplication<?> application;
@Test
void testInvalid(RequestBodySender sender) {
HttpClientResponseException responseException = assertThrows(HttpClientResponseException.class, () ->
sender.send(new Foo("test"))
);
assertEquals(HttpStatus.BAD_REQUEST, responseException.getStatus());
}
@Test
void testValid(RequestBodySender sender) {
Foo foo = sender.send(new Foo("other"));
assertNotNull(foo);
}
@Client("/test")
interface RequestBodySender {
@Post
Foo send(@Body Foo foo);
}
}
@Introspected
record Foo(String name) {}
@Controller("/test")
class TestController {
@Post
Foo receive(@Body Foo foo) {
return foo;
}
}
@Singleton
class BodyValidator implements BeanCreatedEventListener<NettyServerCustomizer.Registry>, NettyServerCustomizer {
private static final String BODY_AGGREGATOR = "body-aggregator";
private static final String BODY_VALIDATOR = "body-validator";
private final Channel channel;
private final HttpServerConfiguration serverConfiguration;
public BodyValidator(@Nullable Channel channel, HttpServerConfiguration serverConfiguration) {
this.channel = channel;
this.serverConfiguration = serverConfiguration;
}
@Override
public NettyServerCustomizer.Registry onCreated(BeanCreatedEvent<NettyServerCustomizer.Registry> event) {
NettyServerCustomizer.Registry registry = event.getBean();
registry.register(this);
return registry;
}
@Override
public NettyServerCustomizer specializeForChannel(Channel channel, ChannelRole role) {
return new BodyValidator(channel, serverConfiguration);
}
@Override
public void onStreamPipelineBuilt() {
if (channel != null) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addBefore(HANDLER_HTTP_STREAM, BODY_AGGREGATOR, new HttpObjectAggregator((int) serverConfiguration.getMaxRequestSize()));
pipeline.addAfter(BODY_AGGREGATOR, BODY_VALIDATOR, new SimpleChannelInboundHandler<FullHttpRequest>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
byte[] bytes = ByteBufUtil.getBytes(msg.content());
// validate bytes
String s = new String(bytes, StandardCharsets.UTF_8);
if (s.contains("test")) {
ctx.writeAndFlush(
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, new HttpResponseStatus(HttpResponseStatus.BAD_REQUEST.code(), "Request failed validation"))
).addListener(listener -> channel.close());
} else {
ctx.fireChannelRead(msg);
}
}
});
}
}
}