0

我正在尝试实现一个过滤器,该过滤器位于我的所有路由中并提取标头并将可能的令牌与存储在我的系统上的内容匹配。

我想实现类似翘曲拒绝示例的东西,但我得到了错误

期望一个实现该Fn特征的闭包,但这个闭包只实现FnOnce 闭包是FnOnce因为它将变量tmp移出其环境

我有点明白编译器在说什么,但不知道如何解决它。我以为做let tmp = store.clone()会。

我有过滤器:

pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {

   let tmp = store.clone();

    warp::header("Authorization").and_then (|auth_header: String| async move {

        // Authorization: BEARER authToken=xxxyyyzzz
        let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {

        if result.is_err() {
            return Err(reject::custom(HayStackAuthToken));
        }

        let (_, key_value) = result.unwrap();

        let auth_token_result = tmp.read().get_authtoken();

        if auth_token_result.is_err() {
            return Err(reject::custom(HayStackAuthToken));
        }

        let auth_token_option = auth_token_result.unwrap();

        if auth_token_option.is_none() {
            return Err(reject::custom(HayStackAuthToken));
        }

        let auth_token = auth_token_option.unwrap();

        if auth_token != key_value.1 {
            return Err(reject::custom(HayStackAuthToken));
        }

        Ok(tmp)
    })
}

storetype Store = Arc<RwLock<Box<dyn UserAuthStore>>>UserAuthStoretrait UserAuthStore: fmt::Debug + Send + Sync

UserAuthStore 定义为

pub trait UserAuthStore: fmt::Debug + Send + Sync {

    // Return handshake token for username. If user has no handshake token generate one
    fn get_handshake_token(&self, username: &str) -> HaystackResult<String>;
    fn get_username(&self, handshake_token: &str) -> HaystackResult<String>;

    fn set_temporary_value(&mut self, k: &str, v: &str) -> HaystackResult<()>;
    fn get_temporary_value(&self,  k: &str) -> HaystackResult<Option<&String>>;

    fn set_authtoken(&mut self, s: String) -> HaystackResult<()>;

    /// returns a base64 encoded sha256 salt of password.
    fn get_password_salt(&self) -> HaystackResult<String>;
    fn get_salted_password(&self) -> HaystackResult<String>;
    fn get_authtoken(&self) -> HaystackResult<Option<String>>;
}

为什么clone在这里不起作用?

完整的错误是

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
    --> src/server/mod.rs:997:45
     |
997  |       warp::header("Authorization").and_then (|auth_header: String| async move {
     |  ___________________________________--------__^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
     | |                                   |         |
     | |                                   |         this closure implements `FnOnce`, not `Fn`
     | |                                   the requirement to implement `Fn` derives from here
998  | |
999  | |         // Authorization: BEARER authToken=xxxyyyzzz
1000 | |         let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {
...    |
1026 | |         Ok(tmp.clone())
1027 | |     })
     | |_____- closure is `FnOnce` because it moves the variable `tmp` out of its environment

你可以在这里看到一个简化的测试用例

4

2 回答 2

3

在创建了一个简单的测试用例之后,我设法使用以下功能让它运行起来。

pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {

    warp::header("Authorization").and_then (
        
            move |auth_header: String| 
            {
                let tmp = store.clone();
                async move {

                    let tmp = tmp.clone();

                    if tmp.read().get_authtoken().is_none() {
                        return Err(reject::custom(HayStackAuthToken));   
                    }
                    
                    Ok(tmp.clone())
                }
            }
    )
}

所以最后只需要在正确的地方克隆。

于 2020-07-28T16:37:12.313 回答
0

fn这个问题表明您对层次结构 还没有明确的区别:在此处输入图像描述 取自这里

Warp 的过滤功能需要实现Fn trait。这意味着您无法访问外部上下文(阅读:环境)。

第一次 AndThen 调用您的闭包时,该函数将使用“唯一”可用的 tmp 变量,因此它将不适用于将来的调用。由于关闭它拥有其上下文的所有权,这意味着它正在实现 FnOnce。

正如@msrd0 在评论中所建议的那样,这可能可以通过在函数中移动该调用来解决,但我需要一个 MRE 来确定它。

于 2020-07-28T15:53:27.630 回答