Redis & Sessions#
Redis can act as a storage provider for caching session data such as user credentials.
If a custom RedisSessionsDelegate isn’t provided, a default will be used.
Default Behavior#
SessionID Creation#
Unless you implement the makeNewID() method in your own RedisSessionsDelegate, all SessionID values will be created by doing the following:
Generate 32 bytes of random characters
base64 encode the value
For example: Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=
SessionData Storage#
The default implementation of RedisSessionsDelegate will store SessionData as a simple JSON string value using Codable.
Unless you implement the makeRedisKey(for:) method in your own RedisSessionsDelegate, SessionData will be stored in Redis with a key that prefixes the SessionID with vrs- (Vapor Redis Sessions)
For example: vrs-Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=
Registering A Custom Delegate#
To customize how the data is read from and written to Redis, register your own RedisSessionsDelegate object as follows:
import Redis
struct CustomRedisSessionsDelegate: RedisSessionsDelegate {
// implementation
}
app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate()))
RedisSessionsDelegate#
API Documentation:
RedisSessionsDelegate
An object that conforms to this protocol can be used to change how SessionData is stored in Redis.
Only two methods are required to be implemented by a type conforming to the protocol: redis(_:store:with:) and redis(_:fetchDataFor:).
Both are required, as the way you customize writing the session data to Redis is intrinsically linked to how it is to be read from Redis.
RedisSessionsDelegate Hash Example#
For example, if you wanted to store the session data as a Hash in Redis, you would implement something like the following:
func redis<Client: RedisClient>(
_ client: Client,
store data: SessionData,
with key: RedisKey
) -> EventLoopFuture<Void> {
// stores each data field as a separate hash field
return client.hmset(data.snapshot, in: key)
}
func redis<Client: RedisClient>(
_ client: Client,
fetchDataFor key: RedisKey
) -> EventLoopFuture<SessionData?> {
return client
.hgetall(from: key)
.map { hash in
// hash is [String: RESPValue] so we need to try and unwrap the
// value as a string and store each value in the data container
return hash.reduce(into: SessionData()) { result, next in
guard let value = next.value.string else { return }
result[next.key] = value
}
}
}