🥠Sessions as a `tower` and `axum` middleware.
🥠Sessions as a `tower` and `axum` middleware.
This crate provides sessions, key-value pairs associated with a site
visitor, as a tower
middleware.
It offers:
SessionStore
trait, fully decoupling sessions from their
storage.axum
Extractor for Session
: Applications built with axum
can use Session
as an extractor directly in their handlers. This makes
using sessions as easy as including Session
in your handler.RedisStore
, SQLx
(SqliteStore
, PostgresStore
, MySqlStore
), and MongoDBStore
stores
are available via their respective feature flags.CachingSessionStore
, applications can leverage a
cache such as MokaStore
to reduce roundtrips to the store when loading
sessions.Serialize
and can
be converted to JSON, it's straightforward to insert, get, and remove any
value.To use the crate in your project, add the following to your Cargo.toml
file:
[dependencies]
tower-sessions = "0.3.3"
axum
Exampleuse std::net::SocketAddr;
use axum::{
error_handling::HandleErrorLayer, response::IntoResponse, routing::get, BoxError, Router,
};
use http::StatusCode;
use serde::{Deserialize, Serialize};
use time::Duration;
use tower::ServiceBuilder;
use tower_sessions::{MemoryStore, Session, SessionManagerLayer};
const COUNTER_KEY: &str = "counter";
#[derive(Default, Deserialize, Serialize)]
struct Counter(usize);
#[tokio::main]
async fn main() {
let session_store = MemoryStore::default();
let session_service = ServiceBuilder::new()
.layer(HandleErrorLayer::new(|_: BoxError| async {
StatusCode::BAD_REQUEST
}))
.layer(
SessionManagerLayer::new(session_store)
.with_secure(false)
.with_max_age(Duration::seconds(10)),
);
let app = Router::new()
.route("/", get(handler))
.layer(session_service);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler(session: Session) -> impl IntoResponse {
let counter: Counter = session
.get(COUNTER_KEY)
.expect("Could not deserialize.")
.unwrap_or_default();
session
.insert(COUNTER_KEY, counter.0 + 1)
.expect("Could not serialize.");
format!("Current count: {}", counter.0)
}
You can find this example as well as other example projects in the example directory.
[!NOTE] See the crate documentation for more usage information.
This crate uses #![forbid(unsafe_code)]
to ensure everything is implemented in 100% safe Rust.
We've put together a number of examples to help get you started. You're also welcome to open a discussion and ask additional questions you might have.
We appreciate all kinds of contributions, thank you!