混合环的 `wrap-defaults`' 和 lib-noir 的 `wrap-noir-session` 时出现奇怪的 session 管理错误

Weird session management bug when mixing ring's `wrap-defaults`' and lib-noir's `wrap-noir-session`

我有一个使用 noir.sessionring 网络应用程序,如下所示:

(def app (-> app-routes
         (session/wrap-noir-session)
         (wrap-defaults site-defaults))) ; both from ring.middleware.defaults

但是,似乎 session 变量在请求之间丢失了。服务器不断发送 Set-Cookie header 即使客户端提供了 Cookie header.

通过反复试验,我发现当我如下禁用环的 anti-forgery 包装器时,相同的 session 存在于请求中:

(def app (-> app-routes
         (session/wrap-noir-session)
         (wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))))

但我当然不想要那样。为什么会这样,如何在不冒 CSRF 攻击风险的情况下解决我的问题?

浏览所有涉及的中间件的源代码,我发现 lib-noir 的 wrap-noir-session 重新实现了 ring 的 wrap-session 的部分内容。这让我进行了以下实验:

(def app (-> app-routes
         (session/wrap-noir-session {:store (memory-store)})
         (wrap-defaults (assoc site-defaults :session false))))

在这里,会话也跨请求存在。

罪魁祸首:wrap-defaults 已经应用了 wrap-session,因此当 wrap-noir-session 处理程序也被列出时,wrap-session 实际上被调用了两次。

最终的解决方案再简单不过了:改用wrap-noir-session*根据文档,它"expects that wrap-session has already been used." 好像wrap-noir-session.

正好相反
(def app (-> app-routes
         (session/wrap-noir-session*)
         (wrap-defaults site-defaults)))

希望这能为您节省一些时间。