2

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`

enter image description here

Kylo_Entro
  • 46
  • 5
  • 1
    You can try adding [`#[debug_handler]`](https://docs.rs/axum/latest/axum/attr.debug_handler.html) to your `get_users` function to see if you can get better insight. – kmdreko Apr 10 '23 at 19:04
  • 1
    Oh many thanks. By adding this, it tells me my `User` is not closable. After adding the `derive(Clone)`, it works ! Thank you !!! – Kylo_Entro Apr 10 '23 at 19:54

0 Answers0