【问题标题】:HTTPS requests with Clojure and RingClojure 和 Ring 的 HTTPS 请求
【发布时间】:2017-03-01 09:21:49
【问题描述】:

我正在使用 RingCompojure 开发 Clojure Web API。 API 需要能够接受基于指定路由的 HTTP 和 HTTPS 请求。

例如:

考虑以下应用程序路由

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

我希望 route-one 只接受 HTTP 请求,route-two 只接受 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})

根据我在网上阅读的内容,Ring HTTPS 请求的标准程序是使用 nginx 作为反向代理来管理所有 HTTPS 请求。

但是我在网上没有找到任何实现。

有什么想法吗?

【问题讨论】:

  • 你看过pedestal.io了吗?它具有用于处理多个“服务器”的配置,我认为这适合您的情况。

标签: nginx https clojure routes ring


【解决方案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 值来实现相同的目的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    相关资源
    最近更新 更多