Expand description
§rainier-session
Sessions: the Session bag a handler reads and writes, the
SessionStore port it is persisted through, and the StartSession
middleware that ties them to a cookie.
use rainier_session::{MemorySessionStore, SessionRequestExt, StartSession, SessionStore};
use rainier_http::{Request, Response};
use rainier_middleware::{Middleware, Pipeline};
use std::sync::Arc;
let store = Arc::new(MemorySessionStore::default());
let start: Arc<dyn Middleware> =
Arc::new(StartSession::new(Arc::clone(&store) as Arc<dyn SessionStore>));
let response = Pipeline::new()
.through_arc(start)
.then(|request: Request| async move {
let session = request.session().expect("StartSession ran");
session.put("user_id", 42u64).unwrap();
Response::text("ok")
})
.run(Request::builder().build())
.await;
assert!(response.header("set-cookie").is_some());§The session is on the request, not on a facade
A session facade can work in PHP because the container rebinds a
request-scoped session per request. Rainier’s facades resolve from a
process-global application, so there is nothing honest for
Session::instance().get(…) to return — with two requests in flight, which
one would it be?
So the split is explicit:
request.session() | this request’s bag |
SessionManager (the Session facade) | the store and its settings |
The facade is for what genuinely is application-wide: reading or destroying a session by id, and collecting expired ones.
§Flash data
flash stores a value for exactly one further request —
the redirect-then-show-a-message pattern, with nothing to remember to clean
up:
let session = Session::new();
session.flash("status", "Saved.").unwrap();
// …the request ends, and the next one can read it.
let next = Session::restore("id", session.age_and_take());
assert_eq!(next.string("status").as_deref(), Some("Saved."));
// …and the one after that cannot.
let later = Session::restore("id", next.age_and_take());
assert!(!later.has("status"));§Drivers
| Driver | Survives a restart | Shared | Revocable | Note |
|---|---|---|---|---|
MemorySessionStore | no | no | yes | development |
DatabaseSessionStore | yes | yes | yes | never evicts |
CacheSessionStore | depends | yes | yes | expires itself; can evict |
CookieSessionStore | yes | yes | no | no server state at all |
A memory store behind a load balancer makes a user’s session appear to vanish and reappear as they are routed around, which looks like a bug in your login code and is not.
The cookie driver is the odd one: the whole session travels encrypted in the cookie, so there is nothing to store and nothing to expire — and nothing to revoke either. A session you cannot see is a session you cannot end.
Re-exports§
pub use cache::CacheSessionStore;pub use cookie::CookieSessionStore;pub use database::DatabaseSessionStore;pub use database::SessionRow;pub use driver::SessionDriver;pub use manager::SessionConfig;pub use manager::SessionManager;pub use middleware::SessionRequestExt;pub use middleware::StartSession;pub use session::generate_session_id;pub use session::Session;pub use session::SessionData;pub use session::TOKEN_KEY;pub use store::is_well_formed;pub use store::MemorySessionStore;pub use store::SessionStore;
Modules§
- cache
CacheSessionStore— sessions in aCache, and so in Redis, a Redis Cluster, or Memcached.- cookie
CookieSessionStore— the whole session, encrypted, in the cookie.- database
DatabaseSessionStore— sessions on the database you already have.- driver
- Where session state lives —
SessionDriver. - manager
SessionManager— the store and its settings, as one container-storable value.- middleware
StartSession— the middleware that loads a session and writes it back.- session
- The session bag —
Sessionand theSessionDatathat is persisted. - store
- Where sessions live — the
SessionStoreport and its implementations.