I am trying Axum to build a web server and I want to protect some routes with JWT. I build a function which take the token from request, check if it is valide then pass a data to handler function.
But I have an error when compiling and I don't understand why
Here my code:
Controller.py
use axum::extract::Extension;
use axum::extract::Json;
use axum::extract::State;
use axum::http::StatusCode;
use axum::middleware;
use axum::response::{IntoResponse, Response};
use axum::routing::{get, post};
use axum::Router;
use diesel::result::Error::DatabaseError;
use crate::app_state::AppState;
use crate::middlewares::jwt_auth::jwt_authentification;
use crate::models::users::{NewUser, User};
use crate::services;
pub async fn create_user(
State(shared_state): State<AppState>,
Json(payload): Json<NewUser>,
) -> Response {
let results = services::users::add_user(payload, shared_state.db_pool.clone());
match results {
Ok(users) => return (StatusCode::CREATED, Json(users)).into_response(),
Err(DatabaseError(..)) => return StatusCode::BAD_REQUEST.into_response(),
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
}
async fn get_users(
State(shared_state): State<AppState>,
Extension(user): Extension<User>,
) -> (StatusCode, Json<Vec<User>>) {
let users = services::users::get_users(shared_state.db_pool.clone());
(StatusCode::OK, Json(users))
}
pub fn return_routes(app_state: AppState) -> Router<AppState> {
let unprotected_route = Router::new().route("/", post(create_user));
let protected_route =
Router::new()
.route("/", get(get_users))
.layer(middleware::from_fn_with_state(
app_state.clone(),
jwt_authentification,
));
return Router::new()
.merge(unprotected_route)
.merge(protected_route);
}
And the JWT auth function
use crate::{app_state::AppState, models::users::UserClaims, services::users::get_user_by_ref};
use axum::{
extract::State,
http::{Request, StatusCode},
middleware::Next,
response::Response,
};
use jsonwebtoken::{DecodingKey, Validation};
const AUTHORIZATION: &str = "authorization";
const BEARER: &str = "Bearer ";
pub async fn jwt_authentification<B>(
State(app_state): State<AppState>,
mut request: Request<B>,
next: Next<B>,
) -> Result<Response, StatusCode> {
let authorization_header = match request.headers().get(AUTHORIZATION) {
Some(v) => v,
None => return Err(StatusCode::UNAUTHORIZED),
};
let authorization = match authorization_header.to_str() {
Ok(v) => v,
Err(_) => return Err(StatusCode::UNAUTHORIZED),
};
if !authorization.starts_with(BEARER) {
return Err(StatusCode::UNAUTHORIZED);
}
let jwt_token = authorization.trim_start_matches(BEARER);
let token_header = match jsonwebtoken::decode_header(&jwt_token) {
Ok(header) => header,
_ => return Err(StatusCode::UNAUTHORIZED),
};
// Get token header
let user_claims = match jsonwebtoken::decode::<UserClaims>(
jwt_token,
&DecodingKey::from_secret(app_state.config.encryption.jwt_secret.as_bytes()),
// &Validation::new(jsonwebtoken::Algorithm::HS256),
&Validation::new(token_header.alg),
) {
Ok(claims) => claims,
_ => return Err(StatusCode::UNAUTHORIZED),
};
let user_ref = user_claims.claims.sub;
let user = match get_user_by_ref(user_ref, app_state.db_pool) {
Ok(user) => user,
_ => return Err(StatusCode::INTERNAL_SERVER_ERROR),
};
request.extensions_mut().insert(user);
Ok(next.run(request).await)
}
I have an error when adding get_user()
function
the trait bound `fn(axum::extract::State<AppState>, Extension<User>) -> impl std::future::Future<Output = (axum::http::StatusCode, axum::Json<Vec<User>>)> {controllers::users::get_users}: Handler<_, _, _>` is not satisfied
the following other types implement trait `Handler<T, S, B>`:
<MethodRouter<S, B> as Handler<(), S, B>>
<axum::handler::Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>rustcClick for full compiler diagnostic
users.rs(41, 25): required by a bound introduced by this call
method_routing.rs(145, 16): required by a bound in `axum::routing::get`