Compojure使用不同的中间件路由 [英] Compojure routes with different middleware

查看:123
本文介绍了Compojure使用不同的中间件路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我试图根据路由应用不同的身份验证代码。考虑下面的代码:

 (defroutes public-routes 
public-endpoint[](PUBLIC ENDPOINT)))

(使用用户路由
(GET/ user-endpoint1 b $ b(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
b $ b

这不能按预期工作,因为 wrap-basic-authentication 确实包装路由,所以它被尝试,无论包装的路由。具体来说,如果请求需要路由到 admin-routes ,仍然会尝试 user-auth?失败)。



我试图使用 context root 基本
路径,但它是一个约束(下面的代码可能不工作,只是为了说明这个想法):

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

我想知道我是否缺少某些东西,或者有任何方式来实现我想要的, code> defroutes 并且不使用公共基本路径(因为理想情况下不会有)。

解决方案<

 (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 *
auth?)))

(defroutes main-routes
(ANY*[] admin-routes)
(ANY*[] user-routes)

这将首先通过管理路由,然后通过用户路由运行传入请求,应用正确的身份验证这里的主要思想是,如果路由不能被调用者访问,而不是抛出一个错误,你的认证函数应该返回 nil ,这样管理路由将返回nil如果a)路由实际上不匹配定义的管理路由或b)用户没有所需的身份验证。如果admin-routes返回nil,用户路由将由compojure尝试。



希望这有帮助。



编辑:我有一段时间写了一篇关于Compojure的帖子,您可能会发现它有用: http:// vedang.me/techlog/2012/02/23/composability-and-compojure


I'm currently writing an API in Clojure using Compojure (and Ring and associated middleware).

I'm trying to apply different authentication code depending on the route. Consider the following code:

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

This doesn't work as expected because wrap-basic-authentication indeed wraps routes so it gets tried regardless of the wrapped routes. Specifically, if the requests needs to be routed to admin-routes, user-auth? will still be tried (and fail).

I resorted to use context to root some routes under a common base path but it's quite a constraint (the code below may not work it's simply to illustrate the idea):

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

I'm wondering if I'm missing something or if there's any way at all to achieve what I want without constraint on my defroutes and without using a common base path (as ideally, there would be none).

解决方案

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

This will run the incoming request first through admin-routes and then through user routes, applying the correct authentication in both cases. The main idea here is that your authentication function should return nil if the route is not accessible to the caller instead of throwing an error. This way admin-routes will return nil if a) the route actually does not match defined admin-routes or b) the user does not have the required authentication. If admin-routes returns nil, user-routes will be tried by compojure.

Hope this helps.

EDIT: I wrote a post about Compojure some time back, which you might find useful: http://vedang.me/techlog/2012/02/23/composability-and-compojure

这篇关于Compojure使用不同的中间件路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆