Rust Actix -从中间件的早期返回



我试图在用户未经过身份验证的情况下从中间件返回一个早期响应。下面是

的代码
if authenticate_pass {
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
Ok(res)
})
} else {
Box::pin(async move {
Ok(HttpResponse::Ok().json("Unauthorized")).into()
})
}

我得到编译错误的确切行是

Ok(HttpResponse::Ok().json("Unauthorized")).into()

,我理解为我试图返回的对象不是预期的。但是,我很困惑这里期望的对象是什么。

得到的错误是:

core::convert::Into
pub fn into(self) -> T
Converts this type into the (usually inferred) input type.
the trait bound `Result<ServiceResponse<B>, actix_web::Error>: 
std::convert::From<Result<HttpResponse, _>>` is not satisfied
the following implementations were found:
<Result<(), idna::uts46::Errors> as std::convert::From<idna::uts46::Errors>>
<Result<(), ring::error::Unspecified> as std::convert::From<ring::bssl::Result>>
<Result<miniz_oxide::MZStatus, miniz_oxide::MZError> as 
std::convert::From<&miniz_oxide::StreamResult>>
<Result<miniz_oxide::MZStatus, miniz_oxide::MZError> as 
std::convert::From<&miniz_oxide::StreamResult>>
and 2 others
required because of the requirements on the impl of `Into<Result<ServiceResponse<B>, 
actix_web::Error>>` for `Result<HttpResponse, _>`rustcE0277

谁能解释一下这里期望的确切返回值是什么?

the trait bound `Result<ServiceResponse<B>, actix_web::Error>: 
std::convert::From<Result<HttpResponse, _>>
...
required because of the requirements on the impl of `Into<Result<ServiceResponse<B>, 
actix_web::Error>>` for `Result<HttpResponse, _>`rustcE0277

表示servicerresponse上没有From<Result<HttpResponse, _>>的实现,(对于Result<HttpResponse, _>>没有Into<Result<ServiceResponse>, _>的实现)

换句话说,该函数期望返回一个Result<ServiceResponse, _>。快速浏览一下文档,就会发现这是预期的类型:https://docs.rs/actix-web/latest/actix_web/dev/struct.ServiceResponse.html

我建议您的中间件收集身份验证状态(以及任何其他相关的授权详细信息),然后向Extensions列表插入一个值。这允许您将Authentication数据注入到处理程序中。

req.extensions_mut().insert::<AuthUserData>(Arc::new(auth_guard));:

中间件:


pub struct SecurityGuardMiddleware<S> {
service: Rc<S>,
}
impl<S: 'static, B> Service<ServiceRequest> for SecurityGuardMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: MessageBody + 'static,
{
type Response = ServiceResponse<BoxBody>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
actix_web::dev::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let svc = self.service.clone();
let mut is_authenticated = true;
let auth_data = Some(true);
Box::pin(async move {
req.extensions_mut()
.insert::<AuthUserData>(Arc::new(auth_data));
let res: ServiceResponse = svc.call(req).await?.map_into_boxed_body();
return Ok(res.map_into_boxed_body());
})
}
}

然后实现FromRequesttrait。注意:在生产示例中,您可能会收集身份验证数据,然后在trait函数from_request中进一步评估它以确定资格。如果您真的想在中间件中对其求值,您可以立即直接修改主体并返回一个新的servicerresponse。也可以直接在中间件中操作扩展。:


impl FromRequest for PortalAuthenticated {
type Error = Error;
type Future = Ready<Result<Self, Self::Error>>;
fn from_request(
req: &actix_web::HttpRequest,
_payload: &mut actix_web::dev::Payload,
) -> Self::Future {
let value = req.extensions().get::<AuthUserData>().cloned();
let mut has_portal_auth = false;
let err_msg = "Request not authorized.";
let result = match value {
Some(auth_user_data) => Ok(PortalAuthenticated(auth_user_data)),
None => Err(actix_web::error::ErrorForbidden(err_msg)),
};
ready(result)
}
}

在你的处理程序中:


#[post("/{id}")]
pub async fn create<'a>(
auth: PortalAuthenticated,
) -> Result<Response<'a, MyStructure>, Error> {
}

最新更新