I'd appreciate a basic Pedestal example of how to (1) setup cookies that survive server restarts and (2) use cookie-based sessions; in particular how to get and set values.
I'm a little surprised not to find an example that uses ring.middleware.session/wrap-session
(source code here: https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/session.clj).
According to this Pedestal sample code for using Ring middleware, there are two key things to add to your service.clj
. First, define the session interceptor:
; aliases for namespace :require
[io.pedestal.http.ring-middlewares :as middlewares]
[ring.middleware.session.cookie :as cookie]
(definterceptor session-interceptor
(middlewares/session {:store (cookie/cookie-store)}))
The sample code has this caveat, however:
In this example code we do not specify the secret with which the session data is encrypted prior to being sent back to the browser. This has two consequences, the first being that we need to use the same interceptor instance throughout the service so that the session data is readable and writable to all paths. The second consequence is that session data will become unrecoverable when the server process is ended. Even though the browser retains the cookie, it is not unrecoverable cipher-text and the session interceptor will treat it as non-existent.
How do I overcome the above limitations?
And, second, add the session-interceptor
to your routes (the following is my example code):
(defroutes routes
[[["/"
{:get [:root root/index]}
^:interceptors [session-interceptor
(body-params/body-params)
bootstrap/html-body]]]]
I know that the setup steps above cause the Ring middleware to add a :session
key to the request map. So getting is easy: (:session request)
. But how and where do I add to the session? An example would be appreciated.
For now, to answer some of my questions:
Specifying a key means that the cookie-backed sessions will be re-readable after a server restart, as mentioned by Compojure/Ring: Why doesn't a session with cookie-store survive a server restart?. Here is some code that shows how:
; (:require [crypto.random :as random])
(def the-key (random/bytes 16)) ; run once
{:store (cookie-store {:key the-key})}
When it comes to changing the value of a session:
“To set the value of :session, just pass it along with your response. If you don’t need the session changed, leave :session out of your response. If you want to actually clear the session, pass nil as the value of the :session key.” (from: Luke VanderHart and Ryan Neufeld. “Clojure Cookbook.”)