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:
2026-06-19 01:39:42 +02:00
parent 4139330234
commit adda731dc6
41 changed files with 1331 additions and 153 deletions

View File

@@ -2,22 +2,36 @@ pub mod error;
mod repository;
mod serialization;
use domain::SecretStore;
use sqlx::SqlitePool;
use std::sync::Arc;
pub use error::SqliteConfigError;
pub struct SqliteConfigStore {
pool: SqlitePool,
secrets: Option<Arc<dyn SecretStore + Send + Sync>>,
}
impl SqliteConfigStore {
pub async fn new(database_url: &str) -> Result<Self, sqlx::Error> {
Self::with_secrets(database_url, None).await
}
pub async fn with_secrets(
database_url: &str,
secrets: Option<Arc<dyn SecretStore + Send + Sync>>,
) -> Result<Self, sqlx::Error> {
let pool = SqlitePool::connect(database_url).await?;
let store = Self { pool };
let store = Self { pool, secrets };
store.migrate().await?;
Ok(store)
}
pub(crate) fn secrets(&self) -> Option<&(dyn SecretStore + Send + Sync)> {
self.secrets.as_deref()
}
async fn migrate(&self) -> Result<(), sqlx::Error> {
sqlx::query(
"CREATE TABLE IF NOT EXISTS widgets (
@@ -63,6 +77,16 @@ impl SqliteConfigStore {
.execute(&self.pool)
.await?;
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL
)",
)
.execute(&self.pool)
.await?;
Ok(())
}
}