cro-http-session-sqlite
Cro::HTTP::Session::SQLite
NAME
Cro::HTTP::Session::SQLite - An implementation of Cro persistent sessions using SQLite.
SYNOPSIS
use Cro::HTTP::Session::SQLite;
DESCRIPTION
There are dozens of ways we might do session storage; this module handles the case where:
- The database is being accessed using DBIish.
- You're fine with the session state being serialized and stored as a JSON 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.
INSTALLATION
zef install Cro::HTTP::Session::SQLite
FUNCTIONALITY
Store the session data in local SQLite3 file
Auto create the db file and table if missing
Using your own SQLite DBIish connection if required
Encrypted data store using OpenSSL::CryptTools AES256
Session auto cleanup or on every request
Configurable table name and columns
Store the user ID and IP address from the session
Skip creating a session
JSON state storage in a json type column
Base64 state storage when encrypted
IP cookie binding
Database default setup
The table name can be changed
Every column is configurable
The table will be created if missing
CREATE TABLE IF NOT EXISTS sessions (
id varchar(255),
state json,
ip_addr varchar(255),
user_id INTEGER,
expiration TIMESTAMP,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX session_id ON sessions (id);
CREATE INDEX expired_date ON sessions (expiration);
Minimal Cro application setup
class MySession {
has $.user-id;
has $.ip-addr;
method set-logged-in-user($!user-id --> Nil) { }
method is-logged-in(--> Bool) { $!user-id.defined }
}
my $application = route {
before Cro::HTTP::Session::SQLite[UserSession].new();
get -> UserSession $user {
$user.user-id = 123;
$user.ip-addr = '127.0.0.1';
content 'text/plain', "Hello, TEST!";
}
}
my Cro::Service $hello = Cro::HTTP::Server.new:
:host<localhost>, :port(80), :$application;
Here are the keypoints here:
Creates a ./sessions.db file
Cookie expiration time is 30 min
Auto clean the sessions table every 30 min
Prevent session loading if the user IP address doesn't match the stored one
Custom setup
before Cro::HTTP::Session::SQLite[UserSession].new(
expiration => Duration.new(60 * 60), # 60 minutes expiration
cookie-name => 'CustomCookieName',
db-path => '/home/user/app/sessions.db',
restrict-ip-addr => True,
autoclean-every-seconds => 60, # Cleanup the sessions table every 60 seconds
key => ("0" x 32).encode, - Encryption key
iv => ("0" x 16).encode, - Encryption IV
skip-cookie => -> Cro::HTTP::Response $response { # Skip the cookie if the request is application/json
my $content-type = $response.request.header('content-type');
$content-type && $content-type eq 'application/json'
}
);
Here we have a custom setup:
Expiration time is 60 minutes
Cookie name is CustomCookieName
SQLite DB file is /home/user/app/sessions.db
Cookie is restricted only to the IP address previously stored
Expired sessions are deleted from the DB every 60 seconds
The data is encrypted using a default KEY and IV and you must CHANGE IT
Cookie is ignored if the request content type is application/json
For full setup see the constructor below
Constructor
All fields are optional
DBDish::SQLite::Connection $.db
DBIish connection. Default auto connects
IO::Path $.db-path
Path to the DB SQLite3 file. Default ./sessions.db
Str $.cookie-name
Name of the cookie. Default CroCookie
Duration $.expiration
Expiration duration for the cookie. Default Duration.new( 30*60 )
Int $.autoclean-every-seconds
Session cleanup every X seconds. Default 1800
- -1 Disable session removal
- 0 Delete the expired sessions on every request
- 1+ Delete the expired sessions every X seconds
Str $.sessions-table
Name of the DB table. Default sessions
Str $.id-column
Name of the ID column in the DB. Default id
Str $.state-column
Name of the state column in the DB. Default state
Str $.expiration-column
Name Of the expiration column. Default expiration
Str $.ip-addr-column
Name of the IP address column. Default ip_addr
Str $.user-id-column
Name of the User ID column. Default user_id
Str $.created-column
Name of the Created column. Default created
Str $.ip-addr-field
Field name from your Session object, that is used to store the IP address in the table column $.ip-addr-column. Default ip-addr
- Nil to disable storing the IP address
Str $.user-id-field
Field name from your Session object, that is used to store the User ID in the table column $.user-id-column. Default user-id
- Nil to disable storing the User ID
Bool $.restrict-ip-addr
IP cookie bind. Looksup the $.ip-addr-field from your Session object. Default True
Callable &.skip-cookie
Custom function that can disable the session. Default Nil
Buf() $.key
Encryption key. See OpenSSL for more information
Buf() $.iv
IV. See OpenSSL for more information
Controlling serialized data
Instead of using the Cro::HTTP::Session::SQLite role directly, create a class that composes it.
class MySessionStore does Cro::HTTP::Session::SQLite[MySession] {
method serialize(MySession $s --> Hash) {
# Replace this with your serialization logic.
$s.Capture.hash
}
method deserialize(Str $d --> MySession) {
# Replace this with your deserialization logic.
Session.new(|from-json($d))
}
}
AUTHOR
Denis Kanchev
COPYRIGHT AND LICENSE
Copyright 2025 Denis Kanchev
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.