我最近开始研究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请求都将被阻止。
有几种方法可以绕过这个
-
使用api-defaults代替site-defaults。API -defaults默认配置适用于提供web API和site-defaults中包含的CSRF保护的站点,它适用于更传统的网站,其中post请求是由先前通过get请求交付的表单生成的,并且包含CSRF令牌作为隐藏字段。此解决方案的缺点是,它可能还会禁用您想要包含的其他中间件
-
关闭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-Token
和X-XSRF-Token
在header中传递它。有关详细信息,请参阅ring-anti-forgery的ring中间件文档。