init
This commit is contained in:
56
backend/src/middlewares/jwt.rs
Normal file
56
backend/src/middlewares/jwt.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use axum::{http::HeaderMap, http::header::AUTHORIZATION};
|
||||
use chrono::{Utc, Duration as ChronoDuration};
|
||||
use jsonwebtoken::{EncodingKey, DecodingKey, Header, Validation};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::error::AppError;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Claims {
|
||||
pub sub: String,
|
||||
pub uid: i64,
|
||||
pub iss: String,
|
||||
pub exp: usize,
|
||||
pub typ: String, // access or refresh
|
||||
}
|
||||
|
||||
pub fn encode_token(claims: &Claims, secret: &str) -> Result<String, AppError> {
|
||||
let key = EncodingKey::from_secret(secret.as_bytes());
|
||||
Ok(jsonwebtoken::encode(&Header::default(), claims, &key)?)
|
||||
}
|
||||
|
||||
pub fn decode_token(token: &str, secret: &str) -> Result<Claims, AppError> {
|
||||
let key = DecodingKey::from_secret(secret.as_bytes());
|
||||
let data = jsonwebtoken::decode::<Claims>(token, &key, &Validation::default())?;
|
||||
Ok(data.claims)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AuthUser { pub uid: i64, pub username: String }
|
||||
|
||||
impl<S> axum::extract::FromRequestParts<S> for AuthUser where S: Send + Sync + 'static {
|
||||
type Rejection = AppError;
|
||||
async fn from_request_parts(parts: &mut axum::http::request::Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let headers: &HeaderMap = &parts.headers;
|
||||
let auth = headers.get(AUTHORIZATION).ok_or(AppError::Unauthorized)?;
|
||||
let auth = auth.to_str().map_err(|_| AppError::Unauthorized)?;
|
||||
let token = auth.strip_prefix("Bearer ").ok_or(AppError::Unauthorized)?;
|
||||
let secret = std::env::var("JWT_SECRET").map_err(|_| AppError::Unauthorized)?;
|
||||
let claims = decode_token(token, &secret)?;
|
||||
if claims.typ != "access" { return Err(AppError::Unauthorized); }
|
||||
Ok(AuthUser { uid: claims.uid, username: claims.sub })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_access_claims(uid: i64, username: &str) -> Claims {
|
||||
let iss = std::env::var("JWT_ISS").unwrap_or_else(|_| "udmin".into());
|
||||
let exp_secs: i64 = std::env::var("JWT_ACCESS_EXP_SECS").ok().and_then(|v| v.parse().ok()).unwrap_or(1800);
|
||||
let exp = (Utc::now() + ChronoDuration::seconds(exp_secs)).timestamp() as usize;
|
||||
Claims { sub: username.to_string(), uid, iss, exp, typ: "access".into() }
|
||||
}
|
||||
|
||||
pub fn new_refresh_claims(uid: i64, username: &str) -> Claims {
|
||||
let iss = std::env::var("JWT_ISS").unwrap_or_else(|_| "udmin".into());
|
||||
let exp_secs: i64 = std::env::var("JWT_REFRESH_EXP_SECS").ok().and_then(|v| v.parse().ok()).unwrap_or(1209600);
|
||||
let exp = (Utc::now() + ChronoDuration::seconds(exp_secs)).timestamp() as usize;
|
||||
Claims { sub: username.to_string(), uid, iss, exp, typ: "refresh".into() }
|
||||
}
|
||||
Reference in New Issue
Block a user