Expand description
Cookie-based sessions over tower-sessions (a real, maintained session
engine - the cookie carries only an opaque session ID, actual data
lives server-side in a Store, which is the standard, more secure
pattern rather than shipping session contents in the cookie itself).
Two real backends, chosen by Config::session_driver
(SESSION_DRIVER - "database", the default, or "file"), both
wrapped in one SessionBackend enum so session_layer always
returns the same concrete SessionManagerLayer<SessionBackend> type
regardless of which one is active:
AnySessionStore: a small hand-writtentower_sessions:: SessionStoreimplementation oversqlx::AnyPool- not a third-party per-backend store crate (tower-sessions-sqlx-store, say). That crate’sSqliteStore/MySqlStoreeach need their own concretely- typedSqlitePool/MySqlPool, butlarust_orm::pool()hands out a runtime-genericAnyPool(seelarust_orm::Backend) with no way to recover a concrete pool from it - so a store built directly againstAnyPool, branching its own SQL bylarust_orm::backendthe same way every other framework crate with its own table does (larust-permissions,larust-queue, …), is both the only real option and the one consistent with how the rest of this framework already handles the two backends.FileSessionStore: one file per session understorage/sessions/- Laravel’s ownSESSION_DRIVER=fileequivalent, for an app that would rather not put session churn through its own database at all (especially now thatdocs/GOTCHAS.mddocuments a real production incident SQLite-backed sessions caused under write-heavy load). Only works for a single server - every process sharing this store needs to see the same directory, which a real multi-server deployment behind a load balancer can’t guarantee the way a shared database can.
Neither is an in-memory store: session data needs to survive a process
restart (a deploy, a crash, xr dev’s rebuild-and-restart cycle), not
just live for the lifetime of one process. There’s deliberately no
in-memory option in this crate’s public API at all: an in-memory store
is a real, common trap (an app that “works” in every manual test, then
silently logs everyone out on every deploy) - same shape as Laravel’s
own array session driver being the wrong thing to ship to production.
"file" doesn’t have that problem - real files on disk survive a
restart/crash exactly the way a database row does - which is why it’s
offered even though array deliberately isn’t.
Structs§
- AnySession
Store - A
tower_sessions::SessionStoreoversqlx::AnyPool- see this module’s own doc comment for why this is hand-written rather than a third-party store crate. The session’s ownRecord(id/data/expiry) is stored as one row:dataas a JSON-serializedTEXTcolumn (serde_jsonis already a workspace-wide dependency; no need for a binary encoding crate just for this),expiry_dateas Unix-epoch seconds - the same “epoch seconds asINTEGER” convention every other framework-owned table in this codebase already uses (larust-cache’scache_items,larust-queue’sjobs,larust-notifications’snotifications), nottower-sessions-sqlx-store’s own native-timestamp-column choice. - File
Session Store - A
tower_sessions::SessionStorebacked by plain files on disk, one per session - see this module’s own doc comment for when this is used instead ofAnySessionStore. Each session’sRecordis JSON-encoded (the same [encode]/[decode] helpersAnySessionStoreitself uses) into a file named afterId’s own rendering. - Session
- A session which allows HTTP applications to associate key-value pairs with visitors.
- Session
Manager Layer - A layer for providing
Sessionas a request extension.
Enums§
- Session
Backend - Wraps whichever of
AnySessionStore/FileSessionStoreConfig:: session_driverselected, sosession_layeralways returns the same concreteSessionManagerLayer<SessionBackend>type regardless of which one is active -tower_sessions::SessionManagerLayer<S>is generic over one concreteS, so the alternative to an enum here would be trait- object erasure (Arc<dyn SessionStore>), more machinery for no real benefit over a two-variantmatchin each trait method.
Functions§
- cookie_
name - This app’s own session cookie name, derived from
Config::app_name- public solarust_testing::TestClient::acting_ascan adopt a session by hand-crafting the exact sameCookieheader the router’s own session layer (above) would issue, without needing a real/loginround trip. Must stay the single source of truth for the name: any second place that re-derives it independently risks drifting out of sync with whateversession_layeractually configured. - resolve_
backend - Resolves
Config::session_driverinto the matching, constructed (but not yet prepared - seesession_layer’s ownensure_dir/migratecall for that)SessionBackendvariant. Split out fromsession_layeritself specifically solarust_testing::TestClientcan build a handle over the same backend a router’s own session layer resolved to, without duplicating the driver-selection logic (and risking it drifting out of sync) -TestClient::acting_asforges a session by writing directly through this handle, bypassing a real/loginround trip, so it has to agree with the router on where sessions actually live. Doesn’t callensure_dir/migrateitself: aTestClientis always built over arouterwhose own.with_sessions(...)call already ran them, the same “someone else already prepared this” assumption the database branch has always relied on (TestClient::newnever calledAnySessionStore::migrateeither, even beforeFileSessionStoreexisted). - session_
layer - Builds the session layer for a Larust app, over
pool(typicallylarust_support::orm::pool()) - or, whenConfig::session_driveris"file", over a directory instead,poolgoing unused for this call entirely. Dispatches to whichever ofAnySessionStore/FileSessionStoreis active (see this module’s own doc comment), preparing it before returning: the database store’s idempotentCREATE TABLE IF NOT EXISTS, or the file store’screate_dir_all- no separate migration file needed in any app’sdatabase/migrations/either way. - take
- Reads and clears a “flash” value - like
session.remove(key), but only actually calls it whenkeywas present. Prefer this for a flash- message read that runs on every page view whether or not one was queued (the common Laravel-style “check for a flashed success/error message on every response” pattern - seedemo/app/Http/Controllers/ post_controller.rs’sindexfor a real example).