add auth system: users, login, JWT, protected routes
Domain: User entity, AuthPort/PasswordHashPort/SecretStore ports. Adapters: auth (argon2 hashing, JWT tokens), secret-store (env-based), config-sqlite user repository, http-api auth routes + extractors. Application: auth_service. SPA: login page, auth client, protected router.
This commit is contained in:
@@ -1,21 +1,27 @@
|
||||
pub mod extractors;
|
||||
mod routes;
|
||||
|
||||
use axum::Router;
|
||||
use domain::{BroadcastPort, ClientRegistry, ConfigRepository, EventPublisher, WidgetStateReader};
|
||||
use domain::{
|
||||
AuthPort, BroadcastPort, ClientRegistry, ConfigRepository, EventPublisher, PasswordHashPort,
|
||||
WidgetStateReader,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use tower_http::services::{ServeDir, ServeFile};
|
||||
|
||||
pub struct AppState<C, E, W, B, R> {
|
||||
pub struct AppState<C, E, W, B, R, A, H> {
|
||||
pub config: Arc<C>,
|
||||
pub events: Arc<E>,
|
||||
pub widget_states: Arc<W>,
|
||||
pub broadcaster: Arc<B>,
|
||||
pub clients: Arc<R>,
|
||||
pub auth: Arc<A>,
|
||||
pub hasher: Arc<H>,
|
||||
pub spa_dir: Option<String>,
|
||||
}
|
||||
|
||||
impl<C, E, W, B, R> Clone for AppState<C, E, W, B, R> {
|
||||
impl<C, E, W, B, R, A, H> Clone for AppState<C, E, W, B, R, A, H> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
config: self.config.clone(),
|
||||
@@ -23,12 +29,14 @@ impl<C, E, W, B, R> Clone for AppState<C, E, W, B, R> {
|
||||
widget_states: self.widget_states.clone(),
|
||||
broadcaster: self.broadcaster.clone(),
|
||||
clients: self.clients.clone(),
|
||||
auth: self.auth.clone(),
|
||||
hasher: self.hasher.clone(),
|
||||
spa_dir: self.spa_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn router<C, E, W, B, R>(state: AppState<C, E, W, B, R>) -> Router
|
||||
pub fn router<C, E, W, B, R, A, H>(state: AppState<C, E, W, B, R, A, H>) -> Router
|
||||
where
|
||||
C: ConfigRepository + Send + Sync + 'static,
|
||||
C::Error: std::fmt::Debug + Send,
|
||||
@@ -38,6 +46,8 @@ where
|
||||
B: BroadcastPort + Send + Sync + 'static,
|
||||
B::Error: std::fmt::Debug + Send,
|
||||
R: ClientRegistry + Send + Sync + 'static,
|
||||
A: AuthPort + Send + Sync + 'static,
|
||||
H: PasswordHashPort + Send + Sync + 'static,
|
||||
{
|
||||
let spa_dir = state.spa_dir.clone();
|
||||
|
||||
@@ -54,9 +64,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve<C, E, W, B, R>(
|
||||
pub async fn serve<C, E, W, B, R, A, H>(
|
||||
addr: &str,
|
||||
state: AppState<C, E, W, B, R>,
|
||||
state: AppState<C, E, W, B, R, A, H>,
|
||||
) -> Result<(), std::io::Error>
|
||||
where
|
||||
C: ConfigRepository + Send + Sync + 'static,
|
||||
@@ -67,6 +77,8 @@ where
|
||||
B: BroadcastPort + Send + Sync + 'static,
|
||||
B::Error: std::fmt::Debug + Send,
|
||||
R: ClientRegistry + Send + Sync + 'static,
|
||||
A: AuthPort + Send + Sync + 'static,
|
||||
H: PasswordHashPort + Send + Sync + 'static,
|
||||
{
|
||||
let app = router(state);
|
||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||
|
||||
Reference in New Issue
Block a user