很多人刚学 Axum,会把鉴权中间件直接套到整个 Router 上。
能跑,但不一定对。
因为官方文档明确指出:
Router::layer(...)会对整张路由图都生效Router::route_layer(...)只会在请求已经命中某条路由之后才执行
这在鉴权场景非常重要。
为什么?
因为你通常希望:
不存在的路
-> 404
存在但没权限的路
-> 401 / 403而不是把所有不合法请求都先拦成 401,结果把真正的 404 吃掉。
看例子:
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));这套心智要记住:
route_layer
= 先确认“这条路存在”
= 再做权限检查
= 避免把 404 错误改写成 401还有一个细节:
route_layer 只对调用它之前已经存在的路由生效。
所以先 route(...),再 route_layer(...),别写反。