(ns cookie-login (:use compojure)) (defn clear-login-token [token-key] "Creates an expiration cookie for a given cookie name." (set-cookie token-key "dummy" :expires "Thu, 01-Jan-1970 00:00:01 GMT")) (defn handle-request-with-login-token "Validates login token, handles request, and updates cookies and session repository. If token is invalid or an exception is raised while reading it, the token cookie is expired." [handler request expiry token-key token-maker token-reader] (if-let [session-info (token-reader (get-in request [:cookies token-key]))] (let [response (handler (merge-with merge request {:session session-info})) ; Session variable priority: ; 1) variables set by handler ; 2) session variables from token-reader ; 3) variables from repository session-map (merge (request :session) session-info (response :session))] (merge-with merge response {:session session-map} (token-maker session-info expiry))) (merge (handler request) (clear-login-token token-key)))) ; Default expiration is a week. (def *default-login-token-expiry* (* 1000 60 60 24 7)) (def *default-login-token-key* :login-token) (defn with-cookie-login "Middleware to support automatic cookie login. Must be placed after the with-session middleware! Accepts five configuration options: - token-key: The cookie name to store the login-token under. Defaults to 'login-token'. - expiry: The number of milliseconds a login token is valid for. Defaults to one week. - is-logged-in?: Function to apply to request's session map to determine whether to process login token or not. If a truthy value is returned, then the next handler is called without further processing. - token-maker: Function to generate new login token from session map and milliseconds until login token expiry. - token-reader: Function to generate session map from login token. Should return nil if login token is invalid. " [handler options] (let [token-key (or (options :default-token-key) *default-login-token-key*) expiry (or (options :expiry) *default-login-token-expiry*) is-logged-in? (options :is-logged-in?) token-maker (options :token-maker) token-reader (options :token-reader)] (fn [request] (if (or (is-logged-in? (request :session)) (not (get-in request [:cookies token-key]))) (handler request) (handle-request-with-login-token handler request expiry token-key token-maker token-reader)))))