我需要从我的定制实现ReactiveAuthorizationManager<AuthorizationContext>
的ServerHttpRequest
中提取请求正文.主体有效载荷包含实体的id
.我需要判断请求的授权,以查看请求者是否可以访问该实体.
为了实现它,我创建了一个定制的ServerHttpRequestDecorator
:
public class BodyInterceptingRequest extends ServerHttpRequestDecorator {
private StringBuilder body = null;
public BodyInterceptingRequest(ServerHttpRequest delegate) {
super(delegate);
}
public Flux<DataBuffer> getBody() {
if (body == null) {
return super.getBody();
}
DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
byte[] bytes = getRequestBody().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = bufferFactory.allocateBuffer(bytes.length);
return Flux.just(buffer.write(bytes));
}
public Mono<String> readBody() {
// @formatter:off
return DataBufferUtils.join(super.getBody())
.map((DataBuffer dataBuffer) -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
})
.defaultIfEmpty(new byte[0])
.flatMap(bytes -> {
body = new StringBuilder();
body.append(new String(bytes, StandardCharsets.UTF_8));
return Mono.just(body.toString());
});
// @formatter:on
}
public String getRequestBody() {
return this.body.toString();
}
}
并在定制的ServerWebExchangeDecorator
:
public class RequestBodyInterceptingExchange extends ServerWebExchangeDecorator {
private final BodyInterceptingRequest request;
public RequestBodyInterceptingExchange(ServerWebExchange exchange) {
super(exchange);
this.request = new BodyInterceptingRequest(exchange.getRequest());
}
@Override
public BodyInterceptingRequest getRequest() {
return request;
}
}
我还创建了一个定制的WebFilter
:
public class RequestBodyInterceptingFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(new RequestBodyInterceptingExchange(exchange));
}
}
并在ServerHttpSecurity
年注册为:
http
// other stuff
.addFilterBefore(new RequestBodyInterceptingFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
.build();
现在,上面提到的ReactiveAuthorizationManager<AuthorizationContext>
的自定义实现如下所示:
public class MyAuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) {
// @formatter:off
return Mono.zip(
authentication,
getId(context)
)
.flatMap((Tuple2<Authentication, String> tuple) -> {
Authentication auth = tuple.getT1();
String id = tuple.getT2();
Jwt principal = (Jwt) auth.getPrincipal();
String userId = principal.getSubject();
return // execute some logic and return a Mono boolean
})
.filter(BooleanUtils::isTrue)
.map(AuthorizationDecision::new);
// @formatter:on
}
protected Mono<String> getId(AuthorizationContext context) {
SecurityContextServerWebExchange securityContextExchange = (SecurityContextServerWebExchange) context.getExchange();
RequestBodyInterceptingExchange exchange = (RequestBodyInterceptingExchange) securityContextExchange.getDelegate();
// @formatter:off
return exchange.getRequest()
.readBody()
.flatMap((String requestBody) -> Mono.just(convert(requestBody).getId())); // convert is a method for deserialize JSON to an Object
// @formatter:on
}
}
我可以实现我所需要的.但我有几个问题:
- 这是我想做的事情的正确方式吗?
- 有没有可能
BodyInterceptingRequest
类是错误的,在并发命中的情况下,它提供了错误的信息?我的意思是,如果有两个调用方,Caller1和Caller2,并且他们分别使用请求1和请求2调用API,那么将为Caller1处理请求2,并为Caller2处理请求1. - 在实现
BodyInterceptingRequest
的过程中是否存在内存泄漏的可能性?
我很感谢你对我的方法提出的专家意见.