全书目录

第三十九篇:Axum 完全指南 —— Rust 类型关口宇宙

第十二章:`layer` 和 `route_layer` 的差别 —— 这是 Axum 权限链最容易写错的地方

1 分钟 284 字 第 758 / 962 个阅读单元

很多人刚学 Axum,会把鉴权中间件直接套到整个 Router 上。

能跑,但不一定对。

因为官方文档明确指出:

  • Router::layer(...) 会对整张路由图都生效
  • Router::route_layer(...) 只会在请求已经命中某条路由之后才执行

这在鉴权场景非常重要。

为什么?

因为你通常希望:

text
不存在的路
-> 404

存在但没权限的路
-> 401 / 403

而不是把所有不合法请求都先拦成 401,结果把真正的 404 吃掉。

看例子:

rust
use axum::{
    extract::Request,
    http::{header::AUTHORIZATION, StatusCode},
    middleware::{self, Next},
    response::{IntoResponse, Response},
    routing::get,
    Router,
};

async fn require_bearer(request: Request, next: Next) -> Result<Response, StatusCode> {
    let token = request
        .headers()
        .get(AUTHORIZATION)
        .and_then(|value| value.to_str().ok());

    match token {
        Some("Bearer gate-secret") => Ok(next.run(request).await),
        _ => Err(StatusCode::UNAUTHORIZED),
    }
}

let app = Router::new()
    .route("/internal/reports", get(internal_reports))
    .route_layer(middleware::from_fn(require_bearer));

这套心智要记住:

text
route_layer
= 先确认“这条路存在”
= 再做权限检查
= 避免把 404 错误改写成 401

还有一个细节:

route_layer 只对调用它之前已经存在的路由生效。 所以先 route(...),再 route_layer(...),别写反。