You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现axum-login的AuthnBackend trait时遭遇生命周期不匹配错误

实现axum-login的AuthnBackend trait时遭遇生命周期不匹配错误

嗨,我刚碰到过类似的问题,来帮你理一理!你遇到的生命周期错误,核心原因是axum-login的AuthnBackend trait里的方法,和你用async fn实现时生成的Future生命周期没有对齐。具体来说,问题主要出在get_user方法的参数处理上,另外我们也可以顺便优化一些细节避免其他潜在问题。

问题拆解

Rust的async fn会被自动展开成返回一个Future,这个Future会捕获方法里的引用(比如&self和&user_id)。而axum-login的trait对这个Future的生命周期有隐含要求,当你直接使用&UserId<Self>(也就是&u64)时,Future会持有这个引用的生命周期,导致和trait定义的约束不匹配。

解决步骤

1. 修正get_user方法的参数处理

因为u64是Copy类型,我们可以直接解引用user_id拿到它的所有权,这样Future就不需要再持有这个引用的生命周期了,代码修改如下:

async fn get_user(&self, user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> {
    // 解引用拿到所有权,消除引用的生命周期绑定
    let user_id = *user_id;
    
    // Connect to db
    let conn = self.db_con.lock().await;
    
    // Load user data from db
    let user_data = match conn.query_row(
        "SELECT data FROM users WHERE id = ?1", 
        [user_id], // 这里直接用值,不用引用
        |row| row.get::<usize, Vec<u8>>(0),
    ) {
        Ok(data) => data,
        Err(err) => match err {
            rusqlite::Error::QueryReturnedNoRows => {
                return Ok(None);
            }
            _ => return Err(self::UserBackendError::Rusqlite(err)),
        },
    };
    
    // 这里把unwrap改成?,并在错误枚举里添加Serde错误变体
    let user: User = from_slice(&user_data)?;
    Ok(Some(user))
}

2. 修复authenticate方法的反序列化错误处理

你现在用了from_slice(&user_data).unwrap();,这会在反序列化失败时直接panic,非常不健壮。我们需要把它改成错误传播,首先给UserBackendError添加Serde相关的错误变体:

#[derive(Debug, thiserror::Error)]
pub enum UserBackendError {
    #[error(transparent)]
    Rusqlite(#[from] rusqlite::Error),
    #[error(transparent)]
    PasswordVerify(#[from] password_auth::VerifyError),
    #[error(transparent)]
    SerdeCbor(#[from] serde_cbor::Error), // 新增这个变体支持Serde错误传播
}

然后把authenticate里的反序列化代码改成:

let user: User = from_slice(&user_data)?;

3. 确认authenticate方法的生命周期对齐

其实authenticate的错误也是因为类似的隐含生命周期问题,不过当我们确保所有操作都不持有不必要的引用(比如你的代码里creds是所有权传递,本身没问题),再加上上面的修改后,这个错误也会跟着消失。

为什么SQLx的例子没这个问题?

SQLx的query_row是原生异步方法,而且它的连接池设计和rusqlite的同步连接+Mutex模式不同,SQLx的异步API不会引入额外的生命周期绑定,所以没暴露这个问题。而rusqlite是同步库,我们用tokio::sync::Mutex包裹后,需要更小心处理引用的生命周期。

这样修改后,编译器的生命周期错误应该就会消失了,代码也会更健壮~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:14:46