HTTPS-запросы с Clojure и кольцом

#nginx #https #clojure #routes #ring

#nginx #https #clojure #маршруты #кольцо

Вопрос:

Я разрабатываю веб-API Clojure, используя Ring и Compojure. API должен иметь возможность принимать запросы HTTP и HTTPS на основе указанного маршрута.

Например:

Рассмотрим следующие маршруты приложений:

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

Я хочу, чтобы маршрут-один принимал только HTTP-запросы, а маршрут-два принимал только HTTPS-запросы.

Возможно ли это?

Я попытался запустить jetty со следующими настройками:

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

Это позволило API принимать запросы HTTPS, но не блокировало HTTP-запросы к тем же маршрутам.

Я также безуспешно пытался отключить протокол HTTP:

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

Из того, что я прочитал в Интернете, стандартная процедура для кольцевых HTTPS-запросов использует nginx в качестве обратного прокси для управления всеми HTTPS-запросами.

Но я не нашел никакой реализации в Интернете.

Есть идеи?

Комментарии:

1. Вы смотрели на pedestal.io пока? У него есть конфигурация для обработки нескольких «серверов», которая, я думаю, подходит к вашей ситуации.

Ответ №1:

Один из простых способов добиться этого — проверить схему входящего запроса внутри вашего маршрута, например:

 (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"})))
  

Вы, конечно, можете извлечь эту проверку схемы в отдельную функцию или макрос, поэтому, даже если у вас много маршрутов, это может быть жизнеспособным вариантом без лишнего шума в вашем коде.

Если у вас много маршрутов, и вы не хотите добавлять дополнительный вызов или проверку к каждому, то другой способ добиться этого — добавить некоторое промежуточное программное обеспечение в ваше приложение. Промежуточное программное обеспечение может проверять :scheme , включенные в запрос, и отклонять запросы, которые не соответствуют. Например:

 (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"})))
  

Сложность заключается в том, что вы хотите выборочно применять это промежуточное программное обеспечение к некоторым маршрутам, а не к другим, и Compojure не предлагает простого способа сделать это. Если у вас есть какой-то общий путь во всех ваших http-маршрутах и все ваши https-маршруты (для их группировки), вы можете использовать шаблон, подобный этому:

 (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))
  

Здесь вы можете видеть, что промежуточное программное обеспечение применяется к каждому подмножеству маршрутов, и поэтому оно будет выполнено только в том случае, если первая часть пути совпадает. Теперь вы можете добавить столько маршрутов, сколько захотите, а промежуточное программное обеспечение позаботится о проверке схемы для всех из них. Обратите внимание, что этот подход требует, чтобы вы могли каким-либо образом идентифицировать подмножества маршрутов в начальных маршрутах «app-routes», в данном случае я идентифицировал их по пути.

При проверке схемы следует отметить одну вещь: имейте в виду, что это не сработает, если вы решите перенести SSL на балансировщик нагрузки. В этом случае ваше приложение всегда будет получать HTTP (не HTTPS) запросы. Обычно вы можете добиться того же, просто проверив X-Forwarded-Proto заголовок вместо :scheme значения.