56 lines
1.7 KiB
Rust
56 lines
1.7 KiB
Rust
// src/auth/jwt.rs
|
|
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation};
|
|
use serde::{Deserialize, Serialize};
|
|
use time::{Duration, OffsetDateTime};
|
|
use uuid::Uuid;
|
|
use std::sync::OnceLock;
|
|
use crate::auth::models::AuthError;
|
|
|
|
static KEYS: OnceLock<Keys> = OnceLock::new();
|
|
|
|
struct Keys {
|
|
encoding: EncodingKey,
|
|
decoding: DecodingKey,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct Claims {
|
|
pub sub: Uuid, // User ID
|
|
pub exp: i64, // Expiration time
|
|
pub role: String, // User role
|
|
}
|
|
|
|
pub fn init_jwt() -> Result<(), AuthError> {
|
|
let secret = std::env::var("JWT_SECRET")
|
|
.map_err(|_| AuthError::ConfigError("JWT_SECRET must be set".to_string()))?;
|
|
|
|
KEYS.set(Keys {
|
|
encoding: EncodingKey::from_secret(secret.as_bytes()),
|
|
decoding: DecodingKey::from_secret(secret.as_bytes()),
|
|
}).map_err(|_| AuthError::ConfigError("Failed to initialize JWT keys".to_string()))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn generate_token(user_id: Uuid, role: &str) -> Result<String, AuthError> {
|
|
let keys = KEYS.get().ok_or(AuthError::ConfigError("JWT not initialized".to_string()))?;
|
|
|
|
let exp = OffsetDateTime::now_utc() + Duration::hours(24);
|
|
let claims = Claims {
|
|
sub: user_id,
|
|
exp: exp.unix_timestamp(),
|
|
role: role.to_string(),
|
|
};
|
|
|
|
encode(&Header::default(), &claims, &keys.encoding)
|
|
.map_err(|e| AuthError::JwtError(e.to_string()))
|
|
}
|
|
|
|
pub fn validate_token(token: &str) -> Result<Claims, AuthError> {
|
|
let keys = KEYS.get().ok_or(AuthError::ConfigError("JWT not initialized".to_string()))?;
|
|
|
|
decode::<Claims>(token, &keys.decoding, &Validation::default())
|
|
.map(|data| data.claims)
|
|
.map_err(|e| AuthError::JwtError(e.to_string()))
|
|
}
|