Create middleware.rs

use actix_web::{
    dev::Payload, error::ErrorUnauthorized, web, FromRequest, HttpRequest,
};
use jsonwebtoken::{decode, DecodingKey, Validation};
use std::{env, future::Ready, future::ready};

use crate::routes::user::Claims;

pub struct JwtClaims(pub Claims);

impl FromRequest for JwtClaims {
    type Error = actix_web::Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let auth_header = req.headers().get("Authorization");

        if let Some(header_value) = auth_header {
            if let Ok(token) = header_value.to_str() {
                let secret = env::var("SECRET_KEY").expect("JWT_SECRET must be set");
                let decoding_key = DecodingKey::from_secret(secret.as_bytes());
                let validation = Validation::default();

                match decode::<Claims>(token, &decoding_key, &validation) {
                    Ok(token_data) => {
                        return ready(Ok(JwtClaims(token_data.claims)));
                    }
                    Err(e) => {
                        eprintln!("JWT decoding error: {:?}", e);
                        return ready(Err(ErrorUnauthorized("Invalid JWT token")));
                    }
                }
            }
        }
        ready(Err(ErrorUnauthorized("Authorization header missing or invalid")))
    }
}

Endpoint


#[derive(Serialize, Deserialize)]
pub struct GetUserResponse {
    pub username: String,
}

pub async fn get_user(data: web::Data<Store>, claims: JwtClaims) -> Result<web::Json<GetUserResponse>> {
    let store = data.into_inner();
    let user = store.get_user_by_id(claims.0.sub).await.map_err(|e| actix_web::error::ErrorInternalServerError(e.to_string()))?;
    Ok(web::Json(GetUserResponse { username: user.user.username }))
}

Store

pub async fn get_user_by_id(&self, id: String) -> Result<GetUserResponse> {
      let user = sqlx::query_as!(User, "SELECT id, username, password FROM users WHERE id = $1", Uuid::parse_str(&id)?)
          .fetch_one(&self.pool)
          .await?;

      Ok(GetUserResponse {
          user: user,
      })
  }
}