在Ring中,会话(Sessions)的工作方式可能跟你预计的有一点不同,因为Ring试图尽可能的变得函数式化.

会话数据通过请求map中的:sessionkey被传递.下面的例子打印出会话中的当前的用户名.

  1. (use 'ring.middleware.session
  2. 'ring.util.response)
  3.  
  4. (defn handler [{session :session}]
  5. (response (str "Hello " (:username session))))
  6.  
  7. (def app
  8. (wrap-session handler))

为了改变会话数据,你可以添加一个包含更新过后的会话数据的:sessionkey到一个响应中.下一个例子统计了当前会话访问页面的次数.

  1. (defn handler [{session :session}]
  2. (let [count (:count session 0)
  3. session (assoc session :count (inc count))]
  4. (-> (response (str "You accessed this page " count " times."))
  5. (assoc :session session))))

为了完全删除session,在响应中设置:sessionkey为nil:

  1. (defn handler [request]
  2. (-> (response "Session deleted.")
  3. (assoc :session nil)))

如果你想简单的重新创建会话,由于特权提升,添加:recreatekey到会话元数据(metadata)中.这将会导致会话标识符被发送到浏览器,由此去改变.

  1. (defn handler [request]
  2. (-> (response "Session identifier recreated")
  3. (assoc :session (vary-meta (:session request) assoc :recreate true))))

经常性的你想要控制会话cookie在用户的浏览器上存在多长时间.你可以使用:cookie-attrs选项去改变会话cookie的属性:

  1. (def app
  2. (wrap-session handler {:cookie-attrs {:max-age 3600}}))

在这个例子中,cookie的最大生命周期被设置成3600秒,或者1小时.

你也可以使用这个选项确保站点的会话cookie通过HTTPS被保护而不是通过HTTP被泄露:

  1. (def app
  2. (wrap-session handler {:cookie-attrs {:secure true}}))

会话存储

会话数据被存储在会话储存中,Ring里面有两个储存方式:

  • ring.middleware.session.memory/memory-store - 在内存中储存会话
  • ring.middleware.session.cookie/cookie-store - 储存加密的会话到一个cookie上
    默认情况下,Ring存储会话数据在内存中,但是这可以被:store选项重写:
  1. (use 'ring.middleware.session.cookie)
  2.  
  3. (def app
  4. (wrap-session handler {:store (cookie-store {:key "a 16-byte secret"})})

通过实现ring.middleware.session.store/SessionStore protocol,你可以编写自己的会话储存方式:

  1. (use 'ring.middleware.session.store)
  2.  
  3. (deftype CustomStore []
  4. SessionStore
  5. (read-session [_ key]
  6. (read-data key))
  7. (write-session [_ key data]
  8. (let [key (or key (generate-new-random-key))]
  9. (save-data key data)
  10. key))
  11. (delete-session [_ key]
  12. (delete-data key)
  13. nil))

注意当你编写会话,如果这是一个新的会话,key将会是nil的.会话储存方式应该预计是这样的,而且会生成一个随机key.这是十分重要的,这个key不会被猜解出,否则恶意的用户能够访问其他用户的会话数据.