JWT y Middleware
JWT
- Obtener token
- Validar token
use std::env;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use time::{Duration, OffsetDateTime};
pub mod middleware;
#[derive(Serialize, Deserialize)]
struct Claims {
user_id: String,
exp: i64,
}
// Generar token
pub fn get_jwt(id: String) -> Result<String, String> {
let jwt_secret = env::var("JWT_SECRET").expect("JWT_SECRET undefined");
let token = encode(
&Header::default(),
&Claims {
user_id: id,
exp: (OffsetDateTime::now_utc() + Duration::minutes(1)).unix_timestamp(),
},
&EncodingKey::from_secret(jwt_secret.as_bytes()),
)
.map_err(|e| e.to_string());
token
}
// Validar token
pub fn decode_jwt(token: &str) -> Result<String, String> {
let jwt_secret = env::var("JWT_SECRET").expect("JWT_SECRET undefined");
let token_data = decode::<Claims>(
token,
&DecodingKey::from_secret(jwt_secret.as_bytes()),
&Validation::default(),
);
match token_data {
Ok(data) => Ok(data.claims.user_id),
Err(e) => Err(e.to_string()),
}
}
Uso
// 3. Generar token
let token = match jwt::get_jwt(id.to_string()) {
Ok(token) => token,
Err(e) => {
let message = json!({"message": e});
return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(message)));
}
};
Middlware
use axum::{extract::Request, http::StatusCode, middleware::Next, response::IntoResponse, Json};
use serde_json::{json, Value};
use super::decode_jwt;
pub async fn auth_middleware(
req: Request,
next: Next,
) -> Result<impl IntoResponse, (StatusCode, Json<Value>)> {
let auth_header = match req.headers().get("Authorization") {
None => {
let message = json!({"message": "Authorization header not found"});
return Err((StatusCode::UNAUTHORIZED, Json(message)));
}
Some(value) => value,
};
// Convertir a string
let auth_header = match auth_header.to_str() {
Ok(value) => value,
Err(_) => {
let message = json!({"message": "Failed to read Authorization header"});
return Err((StatusCode::UNAUTHORIZED, Json(message)));
}
};
// Verificar si existe el Bearer token
if !auth_header.starts_with("Bearer ") {
let message = json!({"message": "No Bearer token provided"});
return Err((StatusCode::UNAUTHORIZED, Json(message)));
}
// Extraer token
let token = &auth_header[7..];
// Validar token
let resut = decode_jwt(token);
match resut {
Ok(_jwt_payload) => Ok(next.run(req).await),
Err(e) => Err((
StatusCode::UNAUTHORIZED,
Json(json!({"message": e.to_string()})),
)),
}
}
Aplicar middlware
/// Este módulo utiliza
/// - [x] Subgrupo de rutas para aplicar los middlewares
/// - [ ] Middleware en ruta
/// - [ ] Middleware en la raiz (src/router.rs)
pub fn author_routes() -> Router<PgPool> {
let public_routes = Router::new()
.route("/", get(get_all))
.route("/:id", get(get_by_id));
let private_routes = Router::new()
.route("/", post(create_author))
.route("/:id", delete(delete_author))
.route("/:id", patch(update_author))
.layer(middleware::from_fn(auth_middleware));
let merge_routes = Router::new().merge(public_routes).merge(private_routes);
merge_routes
}