具有不同中间件的Compojure路由

38 middleware routes clojure compojure ring

我目前正在使用Compojure(以及Ring和相关的中间件)在Clojure中编写API.

我正在尝试根据路由应用不同的身份验证代码.请考虑以下代码:

(defroutes public-routes
  (GET "/public-endpoint" [] ("PUBLIC ENDPOINT")))

(defroutes user-routes
  (GET "/user-endpoint1" [] ("USER ENDPOINT 1"))
  (GET "/user-endpoint2" [] ("USER ENDPOINT 1")))

(defroutes admin-routes
  (GET "/admin-endpoint" [] ("ADMIN ENDPOINT")))

(def app
  (handler/api
    (routes
      public-routes
      (-> user-routes
          (wrap-basic-authentication user-auth?)))))
      (-> admin-routes
          (wrap-basic-authentication admin-auth?)))))
Run Code Online (Sandbox Code Playgroud)

这不能按预期工作,因为它wrap-basic-authentication实际上包装了路由,因此无论包装路由如何都会尝试它.具体来说,如果需要将请求路由到admin-routes,user-auth?仍将尝试(并失败).

我使出context在一个共同的基本路径部分航线,但它是一个相当的限制(下面的代码可能无法正常工作,它只是说明的想法):

(defroutes user-routes
  (GET "-endpoint1" [] ("USER ENDPOINT 1"))
  (GET "-endpoint2" [] ("USER ENDPOINT 1")))

(defroutes admin-routes
  (GET "-endpoint" [] ("ADMIN ENDPOINT")))

(def app
  (handler/api
    (routes
      public-routes
      (context "/user" []
        (-> user-routes
            (wrap-basic-authentication user-auth?)))
      (context "/admin" []
        (-> admin-routes
            (wrap-basic-authentication admin-auth?))))))
Run Code Online (Sandbox Code Playgroud)

我想知道我是否遗漏了某些东西,或者是否有任何方式可以实现我想要的而不受约束defroutes而不使用公共基本路径(理想情况下,没有任何东西).

ved*_*ang 20

(defroutes user-routes*
  (GET "-endpoint1" [] ("USER ENDPOINT 1"))
  (GET "-endpoint2" [] ("USER ENDPOINT 1")))

(def user-routes
     (-> #'user-routes*
         (wrap-basic-authentication user-auth?)))

(defroutes admin-routes*
  (GET "-endpoint" [] ("ADMIN ENDPOINT")))


(def admin-routes
     (-> #'admin-routes*
         (wrap-basic-authentication admin-auth?)))

(defroutes main-routes
  (ANY "*" [] admin-routes)
  (ANY "*" [] user-routes)
Run Code Online (Sandbox Code Playgroud)

这将首先通过管理路由然后通过用户路由运行传入请求,在两种情况下应用正确的身份验证.这里的主要想法是,nil如果调用者无法访问路由而不是抛出错误,则应返回您的身份验证函数.这样,如果a)路由实际上与定义的管理路由不匹配,或者b)用户没有所需的身份验证,则admin-routes将返回nil.如果admin-routes返回nil,则compojure将尝试用户路由.

希望这可以帮助.

编辑:我在一段时间后写了一篇关于Compojure的帖子,你可能觉得它很有用:https://vedang.me/techlog/2012-02-23-composability-and-compojure/


Jul*_*lio 16

我偶然发现了这个问题,似乎wrap-routes(compojure 1.3.2)优雅地解决了这个问题:

(def app
  (handler/api
    (routes
      public-routes
      (-> user-routes
          (wrap-routes wrap-basic-authentication user-auth?)))))
      (-> admin-routes
          (wrap-routes wrap-basic-authentication admin-auth?)))))
Run Code Online (Sandbox Code Playgroud)


小智 1

我刚刚发现以下不相关的页面解决了相同的问题:

http://compojureongae.posterous.com/using-the-app-engine-users-api-from-clojure

我没有意识到可以使用这种类型的语法(我尚未测试过):

(defroutes public-routes
  (GET "/public-endpoint" [] ("PUBLIC ENDPOINT")))

(defroutes user-routes
  (GET "/user-endpoint1" [] ("USER ENDPOINT 1"))
  (GET "/user-endpoint2" [] ("USER ENDPOINT 1")))

(defroutes admin-routes
  (GET "/admin-endpoint" [] ("ADMIN ENDPOINT")))

(def app
  (handler/api
    (routes
      public-routes
      (ANY "/user*" []
        (-> user-routes
            (wrap-basic-authentication user-auth?)))
      (ANY "/admin*" []
        (-> admin-routes
            (wrap-basic-authentication admin-auth?))))))
Run Code Online (Sandbox Code Playgroud)