0

我正在尝试使用塔式中间件层功能在 grpc 之上(通过 tonic)实现身份验证层。为此,我需要获取请求的主体,包括发送到服务器的 protobuf 有效负载,使用 HMAC 对其进行身份验证,然后在元数据/标头中设置身份验证 HMAC。

但是,我在通过 API 检索请求正文时遇到了一些问题,这似乎没有等待整个请求被概括为小型和大型流式请求。后者在实际向服务器发出请求之前需要在内存中缓冲一个大的主体。由于我可以控制要拦截的请求,并且我知道我的请求足够小,可以在内存中缓冲而没有太多开销,因此这种概括增加了一些我不知道如何处理的复杂性。

我的图层目前看起来像这样:

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是不可变的,因此我们不能调用data()身体。由于请求很小,我可以克隆整个请求,缓冲正文,然后在其上计算 HMAC,然后再将请求转发给inner服务,但我尝试的一切都失败了。但是,理想情况下,可以就地缓冲并转发原件。

我怎样才能得到身体http::Request

4

1 回答 1

1

方法签名按值接受请求:

    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 

这不会改变签名,因为调用者不关心你是否会修改它,因为它是按值传递的。

如何将非 mut 借用升级为 mut 借用安全?

它是安全的(并且可能),因为它是按值传递的,而不是按引用传递的。作为该值的唯一所有者,您可以使其可变或不可变

于 2021-09-11T14:31:50.160 回答