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

如何向Axum处理器传递参数?JWT签名场景疑问

如何在Axum处理器中传递Server的公钥参数生成JWT令牌?

我正在构建一个提供并解码JWT令牌的简易服务器,目前遇到一处关键问题:Server结构体包含路由逻辑与配置项(其中公钥用于签名JWT令牌,使用jwt_simple库实现),但不知道如何将Server的公钥属性传递给auth处理器。

以下是我的代码:

pub struct Server {
    pub host: String,
    pub port: String,
    pub public_key: String,
    pub private_key: String
}

impl Server {
    pub async fn start(&self) {
        let routes = Router::new()
            .route("/", get(check))
            .route("/auth", post(auth));

        let hostport = format!("{}:{}", self.host, self.port);
        let addr: SocketAddr = hostport.parse().expect("invalid host:port pair");
        axum::Server::bind(&addr)
            .serve(routes.into_make_service())
            .await
            .unwrap();
    }
}

async fn auth(Json(payload): Json<LoginInput>) -> impl IntoResponse {
    let token = RS384PublicKey::from_pem("id_like_to_put_Server::public_key_here")
        .sign(Claims::create(Duration::from_hours(1)))?;

    let lo = LoginOutput { token };
    (StatusCode::OK, Json(lo))
}

解决方案:使用Axum的共享状态机制

Axum提供了Router::with_state方法传递共享配置,结合Arc实现多线程安全共享,具体步骤如下:

  1. 用Arc包裹Server实例:
    由于Axum服务器运行在多线程环境,Arc(原子引用计数)能保证状态安全跨线程共享,避免所有权冲突。

  2. 修改Server::start方法传递状态:
    创建路由时,通过with_state把Arc<Server>传入路由上下文。

  3. 在auth处理器中提取状态:
    使用Axum的State提取器获取共享的Server实例,从而访问其中的公钥。

修改后的完整代码:

use std::sync::Arc;
use axum::{Router, extract::State, Json, http::StatusCode};
use jwt_simple::algorithms::RS384PublicKey;
use jwt_simple::prelude::{Claims, Duration};

// 假设LoginInput和LoginOutput已定义
#[derive(serde::Deserialize)]
pub struct LoginInput {
    // 登录字段示例:username, password
}

#[derive(serde::Serialize)]
pub struct LoginOutput {
    token: String,
}

pub struct Server {
    pub host: String,
    pub port: String,
    pub public_key: String,
    pub private_key: String
}

impl Server {
    pub async fn start(self) {
        // 用Arc包裹Server实例,实现共享所有权
        let state = Arc::new(self);
        let routes = Router::new()
            .route("/", get(check))
            .route("/auth", post(auth))
            .with_state(state); // 传入共享状态

        let hostport = format!("{}:{}", state.host, state.port);
        let addr: std::net::SocketAddr = hostport.parse().expect("invalid host:port pair");
        axum::Server::bind(&addr)
            .serve(routes.into_make_service())
            .await
            .unwrap();
    }
}

// 假设check处理器已定义
async fn check() -> &'static str {
    "OK"
}

async fn auth(
    // 提取共享的Server状态
    State(server): State<Arc<Server>>,
    Json(payload): Json<LoginInput>
) -> Result<impl IntoResponse, Box<dyn std::error::Error>> {
    // 从Server实例中获取公钥并签名JWT
    let public_key = RS384PublicKey::from_pem(&server.public_key)?;
    let token = public_key.sign(Claims::create(Duration::from_hours(1)))?;

    let lo = LoginOutput { token };
    Ok((StatusCode::OK, Json(lo)))
}

关键说明:

  • Arc的作用:确保Server实例能在多个请求线程中安全共享,无需复制整个实例。
  • State提取器:Axum会自动从路由上下文中匹配对应类型的状态,需保证处理器中的State<T>类型与with_state传入的类型完全一致。
  • 错误处理:原代码中的?需要处理器返回Result类型,因此修改auth的返回值为Result<impl IntoResponse, Box<dyn Error>>,统一处理JWT签名和公钥解析的错误。

内容的提问来源于stack exchange,提问作者Francesco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:55:16