在塔层检索请求 body 以签署 GRPC 请求
Retrieving the request body in a tower layer to sign GRPC requests
我正在尝试使用塔中间件层功能在 grpc 之上(通过 tonic)实现一个身份验证层。为此,我需要获取请求的 body,包括发送到服务器的 protobuf 负载,使用 HMAC 对其进行身份验证,然后在元数据 / [= 中设置身份验证 HMAC 33=].
但是我在通过 API 检索请求 body 时遇到了一些问题,这似乎没有等待整个请求被概括为小型和大型流媒体请求。后者在实际向服务器发出请求之前需要在内存中缓冲一个大的 body。由于我可以控制要拦截的请求,而且我知道我的请求足够小,可以在内存中进行缓冲而不会产生太多开销,因此这种概括增加了一些我不知道如何处理的复杂性。
我的图层目前看起来像这样:
use http::Request;
use std::task::{Context, Poll};
use tonic::body::BoxBody;
use tonic::codegen::Body;
use tower::{Layer, Service};
pub struct AuthLayer {
hmac_key: Vec<u8>,
}
impl AuthLayer {
pub fn new(hmac_key: Vec<u8>) -> Self {
AuthLayer { hmac_key: hmac_key }
}
}
impl<S> Layer<S> for AuthLayer {
type Service = AuthService<S>;
fn layer(&self, inner: S) -> Self::Service {
AuthService {
hmac_key: self.hmac_key.clone(),
inner,
}
}
}
// This service implements the Log behavior
pub struct AuthService<S> {
hmac_key: Vec<u8>,
inner: S,
}
impl<S> Service<Request<BoxBody>> for AuthService<S>
where
S: Service<Request<BoxBody>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, request: Request<BoxBody>) -> Self::Future {
let _body = dbg!(request.body().data());
// TODO Compute an HMAC over _body
// TODO Set HMAC in metadata / headers
self.inner.call(request)
}
}
它失败了,因为 request
是不可变的,因此我们不能在 body 上调用 data()
。由于请求很小,我可以克隆整个请求,缓冲 body 然后计算 HMAC,然后将请求转发到 inner
服务,但我尝试的一切都失败了.然而,理想情况下,可以就地缓冲并转发原始文件。
如何从 http::Request
中获取 body?
方法签名按值接受请求:
fn call(&mut self, request: Request<BoxBody>) -> Self::Future
因此您可以重新绑定它以使其可变。通过重新绑定它,您 将数据移动 到一个新变量(具有相同的名称),该变量是可变的:
let mut request = request;
let request_body = request.body_mut();
let body = request_body.data();
或者您可以直接在方法上添加 mut
:
fn call(&mut self, mut request: Request<BoxBody>) -> Self::Future
这不会改变签名,因为调用者不关心你是否修改它,因为它是按值传递的。
how is upgrading the non-mut borrow to a mut borrow safe?
它是安全的(也是可能的),因为它是按值传递的,而不是按引用传递的。作为该值的唯一所有者,您可以使其可变或不可变
我正在尝试使用塔中间件层功能在 grpc 之上(通过 tonic)实现一个身份验证层。为此,我需要获取请求的 body,包括发送到服务器的 protobuf 负载,使用 HMAC 对其进行身份验证,然后在元数据 / [= 中设置身份验证 HMAC 33=].
但是我在通过 API 检索请求 body 时遇到了一些问题,这似乎没有等待整个请求被概括为小型和大型流媒体请求。后者在实际向服务器发出请求之前需要在内存中缓冲一个大的 body。由于我可以控制要拦截的请求,而且我知道我的请求足够小,可以在内存中进行缓冲而不会产生太多开销,因此这种概括增加了一些我不知道如何处理的复杂性。
我的图层目前看起来像这样:
use http::Request;
use std::task::{Context, Poll};
use tonic::body::BoxBody;
use tonic::codegen::Body;
use tower::{Layer, Service};
pub struct AuthLayer {
hmac_key: Vec<u8>,
}
impl AuthLayer {
pub fn new(hmac_key: Vec<u8>) -> Self {
AuthLayer { hmac_key: hmac_key }
}
}
impl<S> Layer<S> for AuthLayer {
type Service = AuthService<S>;
fn layer(&self, inner: S) -> Self::Service {
AuthService {
hmac_key: self.hmac_key.clone(),
inner,
}
}
}
// This service implements the Log behavior
pub struct AuthService<S> {
hmac_key: Vec<u8>,
inner: S,
}
impl<S> Service<Request<BoxBody>> for AuthService<S>
where
S: Service<Request<BoxBody>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, request: Request<BoxBody>) -> Self::Future {
let _body = dbg!(request.body().data());
// TODO Compute an HMAC over _body
// TODO Set HMAC in metadata / headers
self.inner.call(request)
}
}
它失败了,因为 request
是不可变的,因此我们不能在 body 上调用 data()
。由于请求很小,我可以克隆整个请求,缓冲 body 然后计算 HMAC,然后将请求转发到 inner
服务,但我尝试的一切都失败了.然而,理想情况下,可以就地缓冲并转发原始文件。
如何从 http::Request
中获取 body?
方法签名按值接受请求:
fn call(&mut self, request: Request<BoxBody>) -> Self::Future
因此您可以重新绑定它以使其可变。通过重新绑定它,您 将数据移动 到一个新变量(具有相同的名称),该变量是可变的:
let mut request = request;
let request_body = request.body_mut();
let body = request_body.data();
或者您可以直接在方法上添加 mut
:
fn call(&mut self, mut request: Request<BoxBody>) -> Self::Future
这不会改变签名,因为调用者不关心你是否修改它,因为它是按值传递的。
how is upgrading the non-mut borrow to a mut borrow safe?
它是安全的(也是可能的),因为它是按值传递的,而不是按引用传递的。作为该值的唯一所有者,您可以使其可变或不可变