multi tenancy part 1

This commit is contained in:
2025-10-22 22:52:59 +02:00
parent 8e3f09774a
commit e175d28c2c
35 changed files with 1288 additions and 314 deletions
+50 -4
View File
@@ -6,13 +6,17 @@ use axum_extra::headers::{authorization::Bearer, Authorization};
use axum_extra::TypedHeader;
use serde::{Deserialize, Serialize};
use crate::{error::AppError, state::AppState};
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 role: String,
pub tenant_id: uuid::Uuid,
}
#[async_trait]
@@ -23,6 +27,10 @@ impl FromRequestParts<AppState> for AuthenticatedUser {
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
@@ -33,10 +41,48 @@ impl FromRequestParts<AppState> for AuthenticatedUser {
.verify_token(bearer.token())
.map_err(|_| AppError::unauthorized())?;
Ok(AuthenticatedUser {
let user = AuthenticatedUser {
user_id: claims.sub,
username: claims.username,
role: claims.role,
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,
})
}
}