89 lines
2.2 KiB
Rust
89 lines
2.2 KiB
Rust
pub mod jwt;
|
|
pub mod password;
|
|
|
|
use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
|
|
use axum_extra::headers::{authorization::Bearer, Authorization};
|
|
use axum_extra::TypedHeader;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{
|
|
error::AppError,
|
|
state::{AppState, PgPooledConnection},
|
|
};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AuthenticatedUser {
|
|
pub user_id: uuid::Uuid,
|
|
pub username: String,
|
|
pub tenant_id: uuid::Uuid,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl FromRequestParts<AppState> for AuthenticatedUser {
|
|
type Rejection = AppError;
|
|
|
|
async fn from_request_parts(
|
|
parts: &mut Parts,
|
|
state: &AppState,
|
|
) -> Result<Self, Self::Rejection> {
|
|
if let Some(user) = parts.extensions.get::<AuthenticatedUser>() {
|
|
return Ok(user.clone());
|
|
}
|
|
|
|
let TypedHeader(Authorization(bearer)) =
|
|
TypedHeader::<Authorization<Bearer>>::from_request_parts(parts, state)
|
|
.await
|
|
.map_err(|_| AppError::unauthorized())?;
|
|
|
|
let claims = state
|
|
.jwt
|
|
.verify_token(bearer.token())
|
|
.map_err(|_| AppError::unauthorized())?;
|
|
|
|
let user = AuthenticatedUser {
|
|
user_id: claims.sub,
|
|
username: claims.username,
|
|
tenant_id: claims.tenant_id,
|
|
};
|
|
|
|
parts.extensions.insert(user.clone());
|
|
|
|
Ok(user)
|
|
}
|
|
}
|
|
|
|
pub struct TenantScopedConn {
|
|
pub conn: PgPooledConnection,
|
|
pub tenant_id: Uuid,
|
|
pub user_id: Uuid,
|
|
pub user: AuthenticatedUser,
|
|
}
|
|
|
|
impl TenantScopedConn {
|
|
pub fn conn(&mut self) -> &mut PgPooledConnection {
|
|
&mut self.conn
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl FromRequestParts<AppState> for TenantScopedConn {
|
|
type Rejection = AppError;
|
|
|
|
async fn from_request_parts(
|
|
parts: &mut Parts,
|
|
state: &AppState,
|
|
) -> Result<Self, Self::Rejection> {
|
|
let user = AuthenticatedUser::from_request_parts(parts, state).await?;
|
|
let tenant_id = user.tenant_id;
|
|
let conn = state.db_for_tenant(tenant_id)?;
|
|
|
|
Ok(Self {
|
|
conn,
|
|
tenant_id,
|
|
user_id: user.user_id,
|
|
user,
|
|
})
|
|
}
|
|
}
|