pub mod jwt;
pub mod password;
use axum::{
extract::{FromRef, FromRequestParts, State},
http::request::Parts,
};
use axum_extra::extract::CookieJar;
use crate::{AppState, error::AppError, models::CurrentUser};
pub const AUTH_COOKIE: &str = "it_session";
pub struct AuthUser(pub CurrentUser);
impl<S> FromRequestParts<S> for AuthUser
where
S: Send + Sync,
AppState: FromRef<S>,
{
type Rejection = AppError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let State(app): State<AppState> = State::from_request_parts(parts, state)
.await
.map_err(|_| AppError::Internal("failed to extract state".into()))?;
let jar = CookieJar::from_request_parts(parts, state)
.await
.map_err(|_| AppError::Internal("failed to extract cookies".into()))?;
let token = jar
.get(AUTH_COOKIE)
.ok_or(AppError::Unauthorized)?
.value()
.to_owned();
let claims =
jwt::verify(&token, &app.jwt_secret).map_err(|_| AppError::Unauthorized)?;
let user = crate::db::users::find_by_id(&app.db, &claims.sub)
.await?
.ok_or(AppError::Unauthorized)?;
Ok(AuthUser(user.into()))
}
}
pub struct MaybeAuthUser(pub Option<CurrentUser>);
impl<S> FromRequestParts<S> for MaybeAuthUser
where
S: Send + Sync,
AppState: FromRef<S>,
{
type Rejection = AppError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match AuthUser::from_request_parts(parts, state).await {
Ok(AuthUser(u)) => Ok(MaybeAuthUser(Some(u))),
Err(AppError::Unauthorized) => Ok(MaybeAuthUser(None)),
Err(e) => Err(e),
}
}
}