如何在actix-web提取器中使用异步代码?

6

我正在使用sqlx访问数据库,在actix-web 2.0.0中实现一个认证提取器。以下是我的代码:

use actix_web::{dev, web, Error, HttpRequest, FromRequest};
use actix_web::error::ErrorUnauthorized;
use futures::future::{ok, err, Ready};
use sqlx::PgPool;
use serde_derive::Deserialize;

use crate::model::User;

#[derive(Debug, Deserialize)]
pub struct Auth {
    user_id: u32,
}

impl FromRequest for Auth {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;
    type Config = ();

    fn from_request(req: &HttpRequest, _: &mut dev::Payload) -> Self::Future {
        use actix_web::HttpMessage;

        let db_pool = req.app_data::<web::Data<PgPool>>().unwrap();
        let error = ErrorUnauthorized("{\"details\": \"Please log in\"}");

        if let Some(session_id) = req.cookie("sessionid") {
            log::info!("Session id {}", session_id);
            // let result = User::find_by_session(db_pool.get_ref(), session_id).await;
            ok(Auth { user_id: 0 })
        } else {
            err(error)
        }

    }
}

当然,在那里我不能使用 await。我看到了一个例子,使用了 type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>> 并返回了 Box::pin(async move { ... }),但我无法使其工作(在 req 的生命周期方面存在问题)。

1个回答

13

我成功完成了它。在async move之前,我提取了cookie,因此req没有任何问题。

use std::pin::Pin;
use futures::Future;
use actix_web::{dev, web, Error, HttpRequest, FromRequest};
use actix_web::error::ErrorUnauthorized;
use sqlx::PgPool;
use serde_derive::Deserialize;

use crate::model::User;

#[derive(Debug, Deserialize)]
pub struct Auth {
    user_id: u32,
}

impl FromRequest for Auth {
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
    type Config = ();

    fn from_request(req: &HttpRequest, _: &mut dev::Payload) -> Self::Future {
        use actix_web::HttpMessage;

        let db_pool = req.app_data::<web::Data<PgPool>>().unwrap().clone();
        let cookie = req.cookie("sessionid");

        Box::pin(async move {
            let error = Err(ErrorUnauthorized("{\"details\": \"Please log in\"}"));

            if let Some(session_id) = cookie {
                let result = User::find_by_session(db_pool.get_ref(), session_id).await;
                // auth code
                Ok(Auth { user_id: 0 })
            } else {
                error
            }
        })
    }
}

非常感谢,我有类似的问题!(整个东西看起来非常丑陋) - Tadeo Hepperle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接