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:
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user