feat(api): admin auth surface (login/logout/me/users/publish) on tower-sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 14:54:03 +02:00
parent 4e7288731a
commit 5135aeee6c
7 changed files with 469 additions and 3 deletions
+26
View File
@@ -1,11 +1,16 @@
//! HTTP API: router, handlers, and OpenAPI document.
mod admin;
mod health;
mod openapi;
mod public;
use axum::Router;
use db::Db;
use time::Duration;
use tower_sessions::cookie::SameSite;
use tower_sessions::{Expiry, SessionManagerLayer};
use tower_sessions_sqlx_store::PostgresStore;
/// Shared application state passed to handlers.
#[derive(Clone)]
@@ -14,13 +19,34 @@ pub struct AppState {
pub db: Db,
/// User-facing product name (from config). Never hardcoded.
pub app_name: String,
/// Whether the session cookie carries the `Secure` attribute (default true;
/// disable only for plain-HTTP self-hosting).
pub cookie_secure: bool,
}
/// Build the application router from shared state.
pub fn build_app(state: AppState) -> Router {
let store = PostgresStore::new(state.db.pool().clone());
let session_layer = SessionManagerLayer::new(store)
.with_name("id")
.with_http_only(true)
.with_secure(state.cookie_secure)
.with_same_site(SameSite::Strict)
.with_expiry(Expiry::OnInactivity(Duration::hours(8)));
Router::new()
.merge(health::routes())
.merge(openapi::routes())
.merge(public::routes())
.merge(admin::routes())
.layer(session_layer)
.with_state(state)
}
/// Create the session store's table if absent. Run once at startup (and in tests
/// before exercising auth). Separate from `Db::migrate` — the session library's own
/// bookkeeping table.
pub async fn migrate_sessions(db: &Db) -> Result<(), sqlx::Error> {
PostgresStore::new(db.pool().clone()).migrate().await
}