Compojure使用不同的中间件路由 [英] Compojure routes with different middleware
问题描述
我目前正在使用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屋!