Crate typed_session_axum
source ·Expand description
Typed-session-axum is a middleware providing cookie-based sessions for axum applications.
SessionLayer
provides client sessions via the typed_session
crate.
Sessions are backed by cookies. These cookies are generated
when they are not found or are otherwise invalid. When a valid, known cookie
is received in a request, the session data is retrieved from the session store using this cookie.
The middleware provides sessions via SessionHandle
. Handlers use the
ReadableSession
and
WritableSession
extractors to read
from and write to sessions respectively.
The middleware expects a SessionStoreConnection
to be present, which represents a connection
to a database used to store the sessions.
See SessionLayer::new
for more details.
Example
Using the middleware with axum is straightforward:
use axum::{routing::get, Router, error_handling::HandleErrorLayer, Extension};
use tower::ServiceBuilder;
use typed_session_axum::{
typed_session::{MemoryStore, NoLogger}, WritableSession, SessionLayer, SessionLayerError,
};
use std::fmt::Display;
use tokio::net::TcpListener;
use http::StatusCode;
#[tokio::main]
async fn main() {
let store = MemoryStore::<i32, _>::new(); // mock database connection for debugging purposes
let session_layer = SessionLayer::<i32, MemoryStore<i32, NoLogger>>::new();
async fn handler(mut session: WritableSession<i32>) {
*session.data_mut() = 42;
}
async fn error_handler<SessionStoreConnectorError: Display, InnerError: Display>(
error: SessionLayerError<SessionStoreConnectorError, InnerError>
) -> (StatusCode, String) {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Error: {error}"),
)
}
let app = Router::new().route("/", get(handler)).layer(
ServiceBuilder::new()
.layer(HandleErrorLayer::new(error_handler)) // handle errors
.layer(session_layer)
.layer(Extension(store)) // provide a connection to the session database
);
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
This middleware may also be used as a generic Tower middleware by making use
of the SessionHandle
extension:
use std::convert::Infallible;
use axum::http::header::SET_COOKIE;
use typed_session_axum::{typed_session::{MemoryStore, NoLogger}, SessionHandle, SessionLayer};
use http::{Request, Response};
use rand::Rng;
use tower::{Service, ServiceBuilder, ServiceExt};
async fn handle<Body: Default>(request: Request<Body>) -> Result<Response<Body>, Infallible> {
let session_handle = request.extensions().get::<SessionHandle<()>>().unwrap();
let mut session = session_handle.write().await;
// Use the session as you'd like.
session.data_mut();
Ok(Response::new(Default::default()))
}
let store = MemoryStore::<(), _>::new(); // mock database connection for debugging purposes
let session_layer = SessionLayer::<(), MemoryStore<(), NoLogger>>::new();
let mut service = ServiceBuilder::new()
.layer(session_layer)
.service_fn(handle);
let mut request = Request::builder().body(String::new()).unwrap();
request.extensions_mut().insert(store); // provide a connection to the session database
let response = service.ready().await?.call(request).await?;
assert!(
response
.headers()
.get(SET_COOKIE)
.unwrap()
.to_str()
.unwrap()
.starts_with("id=")
);
Re-exports
pub use typed_session;
Structs
- An extractor which provides a readable session. A single session may have many readers at the same time, but while a writer exists, no other reader or writer can exist.
- Layer that provides cookie-based sessions. See
SessionLayer::new
for more details. - An extractor which provides a writable session. Note that this provides an exclusive (mutable) reference to the session associated with the HTTP request. If two HTTP requests are made with the same session id, the session may be altered by both requests at the same time, resulting in conflicts in the session store. In this case, the session layer produces an error that needs to be handled.
Enums
- The error type for the session layer.
Type Aliases
- A type alias which provides a handle to the underlying session.