无法在Clojure中完成POST请求



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

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

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"由于无效令牌错误而失败。知道我哪里做错了吗?

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

有几种方法可以绕过这个

  1. 使用api-defaults代替site-defaults。API -defaults默认配置适用于提供web API和site-defaults中包含的CSRF保护的站点,它适用于更传统的网站,其中post请求是由先前通过get请求交付的表单生成的,并且包含CSRF令牌作为隐藏字段。此解决方案的缺点是,它可能还会禁用您想要包含的其他中间件

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

在表单中添加一个隐藏字段,例如使用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)))
  ...
)

或禁用它,不推荐,如:

(def应用(wrap-defaults app-routes (associated -in site-defaults [:security:anti- forged] false))

查看这个github示例。特别是在底部:

ring-defaults默认包含POST请求的防伪造功能

我认为你需要改变默认值的使用,如果你不希望这样:

wrap-defaults routes site-defaults

如果你不想禁用它,你需要提交一个带有令牌的隐藏字段的表单,或者通过X-CSRF-TokenX-XSRF-Token在header中传递它。有关详细信息,请参阅ring-anti-forgery的ring中间件文档。

最新更新