Open ikitommi opened 5 years ago
Just putting in my 2 cents: it would be useful to have :allow-origin
(at the very least) be a RegEx or function. Depending on the case, users might want to modify the other headers as well depending on parts of the request (e.g. origin).
I needed CORS to get my local dev setup with a SPA and backend API working. Ended up writing this interceptor that uses ring-cors.
(s/def ::allow-origin string?)
(s/def ::allow-methods (s/coll-of keyword? :kind set?))
(s/def ::allow-credentials boolean?)
(s/def ::allow-headers (s/coll-of string? :kind set?))
(s/def ::expose-headers (s/coll-of string? :kind set?))
(s/def ::max-age nat-int?)
(s/def ::access-control
(s/keys :opt-un [::allow-origin
::allow-methods
::allow-credentials
::allow-headers
::expose-headers
::max-age]))
(s/def ::cors-interceptor
(s/keys :opt-un [::access-control]))
(def cors-interceptor
{:name ::cors
:spec ::access-control
:compile (fn [{:keys [access-control]} _]
(when access-control
(let [access-control (cors/normalize-config (mapcat identity access-control))]
{:enter (fn cors-interceptor-enter
[ctx]
(let [request (:request ctx)]
(if (or (and (cors/preflight? request)
(cors/allow-request? request access-control)))
(let [resp (cors/add-access-control
request
access-control
cors/preflight-complete-response)]
(assoc ctx
:response resp
:queue nil))
ctx)))
:leave (fn cors-interceptor-leave
[ctx]
(let [request (:request ctx)]
(if (and (cors/origin request)
(cors/allow-request? request access-control))
(if-let [response (:response ctx)]
(assoc ctx
:response
(cors/add-access-control
request
access-control
response)))
ctx)))})))})
Happy to submit a PR if interested.
@kennyjwilli, cleaned up your example a little bit:
(def cors-interceptor
{:name ::cors
:spec ::access-control
:compile (fn [{:keys [access-control]} _]
(when access-control
(let [access-control (cors/normalize-config (mapcat identity access-control))]
{:enter (fn cors-interceptor-enter
[{:keys [request] :as ctx}]
(if (and (cors/preflight? request)
(cors/allow-request? request access-control))
(let [resp (cors/add-access-control
request
access-control
cors/preflight-complete-response)]
(assoc ctx
:response resp
:queue nil))
ctx))
:leave (fn cors-interceptor-leave
[{:keys [request response] :as ctx}]
(cond-> ctx
(and (cors/origin request)
(cors/allow-request? request access-control)
response)
(assoc :response
(cors/add-access-control
request
access-control
response))))})))})
What's the status of this? I like the idea of reitit
supporting CORS configuration. I've been searching for an idiomatic way to whitelist origins for my ring
server and stumbled upon this thread.
So, will this support be included into reitit
?
I just tried to use ring-cors
today, but couldn't make it work.
It seems like the casing of the content-type
header makes it fail to allow a method on this line:
https://github.com/r0man/ring-cors/blob/e762decdd4778f70da0dec2b840c5632da559271/src/ring/middleware/cors.cljc#L72
where the access-control-request-method
header is looked up simply with get-in
, instead of the get-header
function within the same file (copied from ring-core
's ring.util.reponse
.
Since such (presumed) bugs are still present in ring-cors
, it might make sense delaying its inclusion into reitit
, but it feels like such a common use-case, it would be great to include it...
Would really like this to be a default option.
What are the current limitations with the :reitit.ring/default-options-endpoint
solution? I understand it allows for arbitrary logic to be injected. Is the limitation the fact that it needs to be applied to the entire router instead of individual routes (e.g. via route middleware)?
Edit: I guess the missing piece would be adding the headers to the non-preflight requests.
I have no answer, but this I am an interested onlooker! Right now our CSRF is managed with Ring handlers, but it would be cool if it were part of Reitit, as per the code you shared.
Currently, a third party mw/interceptor is needed for CORS. There should be a fast default mw & interceptor for this. Those could be configured either via route data or via mw/interceptor options. Example data format from https://github.com/metosin/reitit/issues/143#issuecomment-422079662:
Some prior work:
Related issues: