clojureringhttp-kit

Can the ring-anti-forgery middleware be applied conditionally?


We have a web application that uses HttpKit to serve requests and a handler wrapped with Ring middleware.

The handler is similar to:

(def handler
  (->  #'req-handler
    (wrap-defaults site-defaults)
    (wrap-content-type-and-encoding)
    (wrap-cookies)
    (wrap-stacktrace)))

In the site-defaults one can find:

 :security  { ...
              :anti-forgery         anti-forgery-setting
              ... }

The application used to serve only requests coming from browsers, but now some of the endpoints respond to API requests, POST operations included.

In the documentation I can read:

This middleware will prevent all HTTP methods except for GET and HEAD from accessing your handler without a valid anti-forgery token.

You should therefore only apply this middleware to the parts of your application designed to be accessed through a web browser. This middleware should not be applied to handlers that define web services.

Is there any way to apply the anti-forgery setting conditionally, or give a different version of the site-defaults depending on the request?.


Solution

  • You can use ring.middleware.conditional's operators to conditionally add middleware. For example, to conditionally add the api-defaults mentioned in the comment of Jochen Bedersdorfer:

    
    (require '[ring.middleware.conditional :as middleware.conditional]
    (require '[ring.middleware.defaults :refer [api-defaults site-defaults])
    
    (defn wrap-api-defaults [handler]
      (wrap-defaults handler api-defaults))
    
    (defn wrap-site-defaults [handler]
      (wrap-defaults handler site-defaults))
    
    (def handler
      (-> #'req-handler
          (middleware.conditional/if-url-starts-with "/api" wrap-api-defaults)
          (middleware.conditional/if-url-doesnt-start-with "/api" wrap-site-defaults)
          (wrap-content-type-and-encoding)
          (wrap-cookies)
          (wrap-stacktrace)))