81 lines
2.9 KiB
Rust
81 lines
2.9 KiB
Rust
use axum::{Json, http::StatusCode};
|
|
use jsonwebtoken::{DecodingKey, EncodingKey, Header, decode, encode};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::models::Claims;
|
|
|
|
/// Error response for JWT token operations.
|
|
///
|
|
/// Returned when token encoding or decoding fails. Used in error responses
|
|
/// for invalid or expired tokens.
|
|
///
|
|
/// # Fields
|
|
/// - `status`: HTTP status text (e.g., "error")
|
|
/// - `message`: Human-readable error description
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct Error {
|
|
pub status: &'static str,
|
|
pub message: String,
|
|
}
|
|
|
|
/// Encodes user information into a JSON Web Token (JWT).
|
|
///
|
|
/// This function creates a new JWT with the provided user ID as the subject,
|
|
/// sets the issued-at and expiration times (60 minutes from now), and signs it
|
|
/// using the given encoding key.
|
|
///
|
|
/// # Arguments
|
|
/// - `header`: The JWT header, specifying the algorithm (e.g., HS256).
|
|
/// - `id`: The user ID (`String`) to be embedded as the subject (`sub`) claim.
|
|
/// - `key`: The `EncodingKey` used to sign the JWT.
|
|
///
|
|
/// # Returns
|
|
/// A `String` representing the encoded JWT.
|
|
///
|
|
/// # Panics
|
|
/// Panics if the token encoding fails for any reason (e.g., invalid key).
|
|
pub fn encode_token(header: &Header, id: String, key: &EncodingKey) -> String {
|
|
let now = chrono::Utc::now();
|
|
let expires = (now + chrono::Duration::minutes(60)).timestamp();
|
|
let claims: Claims = Claims {
|
|
sub: id,
|
|
issued: now.timestamp() as usize,
|
|
expires: expires as usize,
|
|
};
|
|
let token = encode(header, &claims, key);
|
|
return token.expect("token return failed");
|
|
}
|
|
|
|
/// Decodes and validates a JSON Web Token (JWT).
|
|
///
|
|
/// This function attempts to decode a JWT string, validate its signature and claims
|
|
/// using the provided decoding key. It specifically ignores expiration (`validate_exp`)
|
|
/// and "not before" (`validate_nbf`) claims during validation.
|
|
///
|
|
/// # Arguments
|
|
/// - `token`: The JWT string to decode.
|
|
/// - `key`: The `DecodingKey` used to verify the JWT's signature.
|
|
///
|
|
/// # Returns
|
|
/// - `200 OK`: If the token is successfully decoded and verified, returns the extracted `Claims`.
|
|
/// - `401 UNAUTHORIZED`: If the token is invalid, expired, or cannot be decoded,
|
|
/// returns an `UNAUTHORIZED` status code along with a JSON error message.
|
|
pub fn decode_token(token: String, key: &DecodingKey) -> Result<Claims, (StatusCode, Json<Error>)> {
|
|
let mut validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256);
|
|
validation.validate_exp = false;
|
|
validation.validate_nbf = false;
|
|
validation.leeway = 0;
|
|
|
|
let claims = decode::<Claims>(&token, key, &validation)
|
|
.map_err(|err| {
|
|
let message = format!("Invalid Token: {}", err);
|
|
let error = Error {
|
|
status: "error",
|
|
message,
|
|
};
|
|
(StatusCode::UNAUTHORIZED, Json(error))
|
|
})?
|
|
.claims;
|
|
return Ok(claims);
|
|
}
|