An implementation of Cro persistent sessions using Postgres.
There are dozens of ways we might do session storage; this module handles the case where:
- The database is being accessed using
DB::Pg
. - You're fine with the session state being serialized and stored as a string/blob in the database.
If these don't meet your needs, it's best to steal the code from this module into your own application and edit it as needed.
Create a table like this in the database:
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
state TEXT,
expiration TIMESTAMP
);
You can change the table and column names, but will then have to specify them when constructing the session state object.
First, create a session object if you do not already have one. This is a class that holds the session state. We'll be saving/loading its content. For example:
class MySession {
has $.user-id;
method set-logged-in-user($!user-id --> Nil) { }
method is-logged-in(--> Bool) { $!user-id.defined }
}
In the case that:
- You are using the default table/column names
- Your session object can be serialized by serializing its public attributes to JSON, and deserialized by passing those back to new
- You are fine with the default 60 minute session expiration time
Then the only thing needed is to construct the session storage middleware with a database handle and a session cookie name.
my $session-middleware = Cro::HTTP::Session::Pg[MySession].new:
:$db,
:cookie-name('my_app_name_session');
It can then be applied as application or route
-block level middleware.
Pass a Duration
object as the duration
named argument:
my $session-middleware = Cro::HTTP::Session::Pg[MySession].new:
:$db,
:cookie-name('my_app_name_session'),
:duration(Duration.new(15 #`(minutes) * 60));
Pass these named arguments as needed during construction:
sessions-table
id-column
state-column
expiration-column
Instead of using the Cro::HTTP::Session::Pg
role directly, create a
class that composes it.
class MySessionStore does Cro::HTTP::Session::Pg[MySession] {
method serialize(MySession $s) {
# Replace this with your serialization logic.
to-json $s.Capture.hash
}
method deserialize($d --> MySession) {
# Replace this with your deserialization logic.
Session.new(|from-json($d))
}
}