So I’m trying to write authentication middleware for my axum server. I used to authenticate user with access token in every route instead of using middleware. But when I tried to create one, it doesn’t work.
main.rs
#[derive(Debug, Clone)]
pub struct AppState {
pub auth_config: config::Auth,
pub pool: Pool<MySql>,
pub projects: config::Projects,
}
let user_routes = Router::new()
.route("/email", patch(patch_email))
.route("/password", patch(patch_password))
.route("/", delete(delete_user))
.route("/", get(get_user))
.route("/lastLogin", post(handlers::last_login))
.layer(axum::middleware::from_fn_with_state(
state.clone(),
middleware::auth,
));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8001")
.await
.expect("Failed to bind auth");
axum::serve(listener, base_router.into_make_service())
.await
.unwrap();
So as you can see here I have
AppState
with couple of user routes that need authentication, and then I have server initialization. Below routes I have a layer that is using from_fn_with_state function where I pass my state andmiddleware::auth
function
middleware.rs
use axum::{
extract::{Request, State},
http::{HeaderMap, StatusCode},
middleware::Next,
response::Response,
};
use tools::tokens::AccessToken;
use crate::AppState;
pub async fn auth(
State(state): State<AppState>,
headers: HeaderMap,
mut request: Request,
next: Next,
) -> Result<Response, StatusCode> {
match AccessToken::from_headers(&headers) {
Some(token) => {
// Check if token is valid
// If valid, proceed to the next middleware or handler
match token.decode(&state.auth_config.secret).await {
Ok(c) => {
request.extensions_mut().insert(c.id).unwrap();
Ok(next.run(request).await)
},
Err(_) => Err(StatusCode::UNAUTHORIZED),
}
}
None => {
// Return unauthorized response if token is not valid
Err(StatusCode::UNAUTHORIZED)
}
}
}
And this is
auth
function that validates token and passes uid into request
When I put it all together and try to build the project, it shows me this error:
the trait bound `axum::middleware::FromFn<fn(axum::extract::State<AppState>, axum::http::HeaderMap, axum::http::Request<axum::body::Body>, Next) -> impl std::future::Future<Output = Result<axum::http::Response<axum::body::Body>, axum::http::StatusCode>> {auth}, Arc<AppState>, Route, _>: Service<axum::http::Request<axum::body::Body>>` is not satisfied
the following other types implement trait `Service<Request>`:
axum::middleware::FromFn<F, S, I, (T1, T2)>...
main.rs(47, 10): required by a bound introduced by this call
mod.rs(278, 21): required by a bound in `axum::Router::<S>::layer`
How can I fix this?