【问题标题】:Unable to complete POST request in Clojure无法在 Clojure 中完成 POST 请求
【发布时间】:2016-01-12 22:37:56
【问题描述】:

我最近开始探索 Clojure,我想建立一个具有基本 CRUD 功能的简单 Web 应用程序。我在这里找到了一个不错的教程:http://www.xuan-wu.com/2013-09-21-Basic-Web-Application-in-Clojure

GET 请求工作正常,但每当我尝试发布请求时,都会收到以下错误:

Invalid anti-forgery token

我之前提到的教程没有涉及任何与安全相关的内容。我做了一些挖掘,似乎我错过了 Compojure 的一些组件,这些组件应该生成一个用于发出 POST 请求的令牌。有些地方提到我应该自动发生而不需要我做任何改变。我仍然不确定我错过了什么。这是我的代码:

(ns myblog.handler
    (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
            [myblog.views :as views]
            [myblog.posts :as posts]
            [ring.util.response :as resp]
            [ring.middleware.basic-authentication :refer :all]))

(defn authenticated? [name pass]
  (and (= name "user")
       (= pass "pass")))

(defroutes public-routes
    (GET "/" [] (views/main-page))
    (route/resources "/"))

(defroutes protected-routes
    (GET "/admin" [] (views/admin-page))
    (GET "/admin/add" [] (views/add-post))
    (POST "/admin/create" [& params]
        (do (posts/create params)
            (resp/redirect "/admin"))))

(defroutes app-routes
    public-routes
    (wrap-basic-authentication protected-routes authenticated?)
    (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

同样,只有 POST 请求“/admin/create”因无效令牌错误而失败。知道我做错了什么吗?

【问题讨论】:

  • 你是如何发出 POST 请求的?类似curl 或浏览器中的内容?
  • 在浏览器中。我正在向 /admin/create 提交表单。

标签: post clojure compojure antiforgerytoken


【解决方案1】:

您的问题在于 wrap-defaults 和 site-defaults 设置。 site-defaults 默认配置添加了 ant9forgery CSRF 保护,任何不包含有效 CSRF-token 的 post 请求都将被阻止。

有几种方法可以解决这个问题

  1. 使用 api-defaults 而不是 site-defaults。 api-defaults 默认配置适用于您提供 Web API 的站点,并打开 site-defaults 中包含的 CSRF 保护,这适用于更传统的网站,其中发布请求由先前交付的表单生成通过 get 请求并包含 csrf-token 作为隐藏字段。此解决方案的缺点是它还可能禁用您确实希望包含的其他中间件

  2. 在站点默认配置中禁用 csrf 保护。这涉及将映射中的适当键值设置为 false,即
    (wrap-defaults app-routes (assoc-in site-defaults [:security :anti-forgery] false))

【讨论】:

    【解决方案2】:

    在表单中添加隐藏字段,例如使用 enlive-html:

    (ns xxx.html
      (:use [net.cgrand.enlive-html])
      (:require [clojure.string :as str]
                [ring.util.anti-forgery :refer [anti-forgery-field]]))
    
    (deftemplate render-page "base.html"
      [settings]
      [:form#my-form] (append (html-snippet (anti-forgery-field)))
      ...
    )
    

    或者禁用它,不推荐,如:

    (定义应用程序 (wrap-defaults app-routes (assoc-in site-defaults [:security :anti-forgery] false)))

    【讨论】:

    • 如果您使用 Selmer,则在模板中添加隐藏字段的代码为 {{anti-forgery-field|safe}},其中 :anti-forgery-field 是数据映射中的键。
    【解决方案3】:

    请参阅此 github example。尤其是在底部:

    ring-defaults 默认包含 POST 请求的防伪功能(以及 其他修改数据的人)。

    如果您不希望这样做,我认为您需要更改对默认值的使用:

    wrap-defaults routes site-defaults
    

    如果您不想禁用它,您需要提交带有令牌的隐藏字段的表单,或者通过X-CSRF-TokenX-XSRF-Token 在标题中传递它。详情请参阅 ring 中间件docs 了解 ring-anti-forgery。

    【讨论】:

      猜你喜欢
      • 2017-11-23
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 2022-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多