Crate rocket_flex_session

Crate rocket_flex_session 

Source
Expand description

§Overview

Simple, extensible session library for Rocket applications.

  • Session cookies are securely stored and encrypted using Rocket’s built-in private cookies
  • Session guard can be used multiple times during a request, enabling various layers of authentication and authorization through Rocket’s request guard system.
  • Makes use of Rocket’s request-local cache to ensure that only one backend call will be made to get the session data, and if the session is updated multiple times during the request, only one call will be made at the end of the request to save the session.
  • Multiple storage providers available, or you can use your own session storage by implementing the SessionStorage trait.

§Usage

While technically not needed for development, it is highly recommended to set the secret key in Rocket. That way the sessions will stay valid after reloading your code if you’re using a persistent storage provider. The secret key is required for release mode.

§Basic setup

use rocket::routes;
use rocket_flex_session::{Session, RocketFlexSession};

// Create a session data type (this type must be thread-safe and Clone)
#[derive(Clone)]
struct MySession {
    user_id: String,
    // ..other session fields
}

#[rocket::launch]
fn rocket() -> _ {
    rocket::build()
        // attach the `RocketFlexSession` fairing, passing in your session data type
        .attach(RocketFlexSession::<MySession>::default())
        .mount("/", routes![login])
}

// use the `Session` request guard in a route handler
#[rocket::post("/login")]
fn login(mut session: Session<MySession>) {
    session.set(MySession { user_id: "123".to_owned() });
}

§Request guard auth

If a valid session isn’t found, the Session request guard will still succeed, but calling Session.get() or Session.tap() will yield None - indicating an empty/uninitialized session. This primitive is designed for you to be able to add your authentication and authorization layer on top of it using Rocket’s flexible request guard system.

For example, we can write a request guard for our MySession type, that will attempt to retrieve the session data and verify whether there is an active session:

use rocket::{
    http::Status,
    request::{FromRequest, Outcome},
    Request,
};
use rocket_flex_session::Session;

#[derive(Clone)]
struct MySession {
    user_id: String,
    // ..other session fields
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for MySession {
   type Error = &'r str; // or your custom error type

   async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
       // Run the Session request guard (this guard should always succeed)
       let session = req.guard::<Session<MySession>>().await.expect("should not fail");

       // Get the `MySession` session data, or if it's `None`, send an Unauthorized error
       match session.get() {
           Some(my_session) => Outcome::Success(my_session),
           None => Outcome::Error((Status::Unauthorized, "Not logged in")),
       }
    }
 }

 // Use our new `MySession` request guard in a route handler
 #[rocket::get("/user")]
 fn get_user(session: MySession) -> String {
    return format!("Logged in as user {}!", session.user_id);
 }

For more info and examples of this powerful pattern, please see Rocket’s documentation on request guards.

§HashMap session data

Instead of a custom struct, you can use a HashMap as your Session data type. This is particularly useful if you expect your session data structure to be inconsistent and/or change frequently. When using a HashMap, there are some additional helper functions to read and set keys.

use rocket_flex_session::Session;
use std::collections::HashMap;

type MySessionData = HashMap<String, String>;

#[rocket::post("/login")]
fn login(mut session: Session<MySessionData>) {
    let user_id: Option<String> = session.get_key("user_id");
    session.set_key("name".to_owned(), "Bob".to_owned());
}

§Feature flags

These features can be enabled as shown in Cargo’s documentation.

NameDescription
cookieA cookie-based session store. Data is serialized using serde_json and then encrypted into the value of a cookie.
redis_fredA session store for Redis (and Redis-compatible databases), using the fred.rs crate.
sqlx_postgresA session store using PostgreSQL via the sqlx crate.
rocket_okapiEnables support for the rocket_okapi crate if needed.

Modules§

storage
Storage implementations for sessions

Structs§

RocketFlexSession
A Rocket fairing that enables sessions.
RocketFlexSessionBuilder
Builder to configure the RocketFlexSession fairing
Session
Represents the current session state. When used as a request guard, it will attempt to retrieve the session. The request guard will always succeed - if a valid session wasn’t found, session.get() will return None indicating an inactive session.
SessionOptions
Options for configuring the session.