我对铁 rust 还是个新手,现在我在玩Axum. 我想用PKCE实现一个授权码流.因此,我必须将生成的PKCE代码验证器移交给回调路径,以便将代码交换为令牌,这样我就可以继续使用会话等登录我的用户.

现在我主要使用锤子,只是为了描述为什么解决方案可能看起来像这样:

#[derive(Clone)]
struct AppState {
    db: PgPool,
    oauth_client: BasicClient,
    verifiers: Arc<Mutex<HashMap<String, String>>>,
}

#[debug_handler]
async fn callback(
    State(state): State<AppState>,
    Query(auth_request): Query<AuthRequest>,
) -> Result<impl IntoResponse, impl IntoResponse> {
    let auth_request = auth_request;

    let verifiers = state.verifiers.lock().unwrap();
    let pkce_verifier = verifiers.get(&auth_request.state).unwrap().into();
    let pkce_verifier = PkceCodeVerifier::new(pkce_verifier);

    let _token_result = match state
        .oauth_client
        .exchange_code(AuthorizationCode::new(auth_request.code))
        .set_pkce_verifier(pkce_verifier)
        .request_async(async_http_client)
        .await
    {
        Ok(res) => res,
        Err(e) => {
            error!("could not exchange code: {e}");
            return Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()));
        }
    };

    Ok(Redirect::temporary("/"))
}

错误如下:

  --> src/main.rs:134:10
    |
125 |     let verifiers = state.verifiers.lock().unwrap();
    |         --------- has type `std::sync::MutexGuard<'_, std::collections::HashMap<std::string::String, std::string::String>>` which is not `Send`
134 |         .await
    |          ^^^^^ await occurs here, with `verifiers` maybe used later

我知道互斥体的锁定时间太长了.我试着理解了很多类似的问题,但我还不能理解这个.

有人能帮我解决这个可能很琐碎的问题吗?

提前感谢您的帮助.

推荐答案

Rust的std::sync::Mutex不能超过await点,这就是为什么您会看到type is not Send编译错误.您有两个 Select :

  1. 在你到达await点之前放下锁.您只需使用verifiers即可获得pkce_verifier,因此您只需将其内联:

    let pkce_verifier = state
        .verifiers
        .lock()
        .unwrap()
        .get(&auth_request.state)
        .unwrap()
        .into();
    

    这有点难看,所以您也可以手动调用锁上的drop():

    let verifiers = state.verifiers.lock().unwrap();
    let pkce_verifier = verifiers.get(&auth_request.state).unwrap().into();
    drop(verifiers);
    

    或者,您可以在内部块作用域中创建和使用锁,这将在块退出作用域时自动删除锁:

    let pkce_verifier = {
        let verifiers = state.verifiers.lock().unwrap();
        verifiers.get(&auth_request.state).unwrap().into()
    };
    
  2. 你可以使用一个可感知的锁,比如futures::lock::Mutex.如果您认为将来需要在await点上使用互斥锁,那么您可以切换到一个支持互斥锁的互斥锁.否则,只要锁不跨await点持有,标准库互斥就可以工作.


顺便说一句,除非您确定字段存在,否则对对象调用.unwrap()是不好的做法.特别是在HashMap的情况下,您应该使用模式匹配或Rust提供的类似ok_or()的内置OptionResult函数.

Rust相关问答推荐

在Rust中创建可变片段的可变片段的最有效方法是什么?

为什么我需要在这个代码示例中使用&

交叉术语未正确清除屏幕

在使用#[NO_STD]时,如何在Rust中收到紧急消息?

如何向下转换到MyStruct并访问Arc Mutex MyStruct实现的方法?

铁 rust 中双倍或更多换行符的更好练习?

如何对一个特征的两个实现进行单元测试?

从 rust 函数返回 &HashMap

将 &str 或 String 保存在变量中

枚举的利基优化如何在 Rust 中工作?

如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

(let b = MyBox(5 as *const u8); &b; ) 和 (let b = &MyBox(5 as *const u8); ) 之间有什么区别

如何在 Rust 中按 char 对字符串向量进行排序?

具有在宏扩展中指定的生命周期的枚举变体数据类型

我什么时候应该使用特征作为 Rust 的类型?

在异步 Rust 中,Future 如何确保它只调用最近的 Waker?

实现不消费的迭代器

tokio async rust 的 yield 是什么意思?

以下打印数组每个元素的 Rust 代码有什么问题?

C++ 中的 CRTP 是一种表达其他语言中特征和/或 ADT 的方法吗?