2016-10-19 4 views
3

Ich entwickle eine Clojure Web-API mit Ring und Compojure. Die API muss HTTP- und HTTPS-Anforderungen basierend auf der angegebenen Route akzeptieren können.HTTPS-Anfragen mit Clojure und Ring

Zum Beispiel:

Betrachten Sie die folgenden App-Routen:

(defroutes app-routes    
      (POST "/route-one" {request :request} (processRequet request)) 
      (POST "/route-two" {request :request} (processRequet request))) 

Ich mag Route-one nur HTTP-Anforderungen akzeptieren und routen zwei nur HTTPS-Anfragen zu akzeptieren .

Ist das möglich?

Ich versuchte Anlegestelle mit den folgenden Einstellungen ausgeführt wird:

(jetty/run-jetty #'app {:join? false :ssl? true :ssl-port 8443 :keystore "./resources/keystore.jks" :key-password "12345678"}) 

, dass die API HTTPS-Anforderungen akzeptieren aktiviert, aber es HTTP-Anfragen nicht auf die gleichen Routen blockieren.

Ich versuchte auch das HTTP-Protokoll ohne Glück zu deaktivieren:

(jetty/run-jetty #'app {:port 5000 :join? false :ssl? true :ssl-port 8443 :keystore "./resources/keystore.jks" :key-password "12345678" :http? false}) 

Von dem, was ich online gelesen, das Standardverfahren für Ring HTTPS-Anfragen nginx als Reverse-Proxy verwenden alle HTTPS-Anfragen zu verwalten .

Aber ich habe keine Implementierung online gefunden.

Irgendwelche Ideen?

+0

Haben Sie schon http://pedestal.io/ angeschaut? Es hat eine Konfiguration für die Handhabung mehrerer "Server", was meiner Meinung nach zu Ihrer Situation passt. –

Antwort

2

Eine einfache Möglichkeit, dies zu erreichen, ist das Schema der eingehenden Anforderung innerhalb Ihrer Route zum Beispiel zu überprüfen:

(defroutes app-routes 
    (POST "/route-one" request 
     (if (= (:scheme req) :http) 
      (process-requet request) 
      {:status 403 :body "https not supported"})) 
    (POST "/route-two" request 
     (if (= (:scheme req) :https) 
      (process-requet request) 
      {:status 403 :body "http not supported"}))) 

Sie können so auch natürlich extrahieren dieses Schema Prüfung in eine separate Funktion oder ein Makro, Wenn Sie viele Routen haben, dann könnte dies eine praktikable Option sein, ohne zu viel Rauschen in Ihrem Code.

Wenn Sie viele Routen haben und keinen zusätzlichen Anruf oder eine Überprüfung hinzufügen möchten, können Sie eine weitere Middleware zu Ihrer Anwendung hinzufügen. Die Middleware kann die in der Anfrage enthaltene Nummer :scheme prüfen und nicht konforme Anfragen ablehnen. Zum Beispiel:

(defn wrap-https-only [handler] 
    (fn [req] 
    (if (= (:scheme req) :https) 
     (handler req) 
     {:status 403 :body "http not supported"}))) 

(defn wrap-http-only [handler] 
    (fn [req] 
    (if (= (:scheme req) :http) 
     (handler req) 
     {:status 403 :body "https not supported"}))) 

Der schwierige Teil ist, dass Sie diese Middleware auf einigen Strecken selektiv anwenden möchten und andere nicht, und Compojure keine einfache Möglichkeit bieten, dies zu tun. Wenn Sie einige gemeinsamen Weg in alle http Routen haben, und alle Ihre https Routen (zu gruppieren), dann können Sie ein Muster wie folgt verwenden:

(def http-routes 
    (-> (routes (POST "/http-only/route-one" request 
        (process-requet request))) 
     wrap-http-only)) 

(def https-routes 
    (-> (routes (POST "/http-only/route-two" request 
        (process-requet request))) 
     wrap-https-only)) 


(defroutes app-routes 
    (ANY "/http-only/*" [] http-routes) 
    (ANY "/https-only/*" [] https-routes)) 

Sie hier sehen können, dass die Middleware zu jeder Teilmenge angewendet wird von Routen, und so wird es nur ausgeführt, wenn der erste Teil des Pfades übereinstimmt. Jetzt können Sie so viele Routen hinzufügen, wie Sie möchten, und die Middleware kümmert sich um die Schemaüberprüfung für alle von ihnen.Beachten Sie, dass dieser Ansatz erfordert, dass Sie die Teilmengen von Routen in irgendeiner Weise auf den ersten "App-Routen" -Routen identifizieren können, in diesem Fall habe ich sie anhand des Pfads identifiziert.

Eine Sache zu beachten, wenn Sie das Schema überprüfen: Seien Sie gewarnt, dass dies nicht funktioniert, wenn Sie SSL an einen Load Balancer auslagern möchten. In diesem Fall erhält Ihre Anwendung immer HTTP-Anfragen (nicht HTTPS). Sie können das gleiche erreichen, indem Sie einfach den X-Forwarded-Proto Header anstelle des :scheme Wertes überprüfen.

Verwandte Themen