I have two sets of compojure routes, public ones, which need no authentication, and private ones which need authentication.
(defroutes public-routes
(GET "/" [] homepage-handler))
(defroutes private-routes
(GET "/secrets" [] secrets-handler))
I created a middleware which checks is the user authenticated and either continues the middleware chain or raises.
(defn wrap-must-be-authenticated [handler]
(fn [request]
(if (authenticated? request)
(handler request)
(throw-unauthorized))))
(def app
(-> private-routes
(wrap-must-be-authenticated)))
This works fine, all "private routes" require authentication.
How would I go about adding the public-routes
so they are excluded from wrap-must-be-authenticated
?
I believe defroutes
returns ring handlers, so I'm thinking I need to do something like:
(-> (wrap-must-be-authenticated private-routes)
public-routes)
One way to do this is to put multiple routes
definitions in a containing routes
, and wrap (wrap-routes
) the appropriate routes in middleware to restrict access:
(def all-routes
(routes
(-> #'private-routes
(wrap-routes wrap-must-be-authenticated))
#'public-routes
(route/not-found
(:body
(error-page {:status 404
:title "page not found"})))))
Another example from a project where I'm using buddy.auth's restrict
:
(defn wrap-admin [handler]
(restrict handler {:handler (fn [req]
(boolean (get-in req [:session :admin?])))}))
(def app-routes
(routes
(-> #'admin-routes
(wrap-routes wrap-admin)
(wrap-routes middleware/wrap-csrf)
(wrap-routes middleware/wrap-formats))
(-> #'home-routes
(wrap-routes middleware/wrap-csrf)
(wrap-routes middleware/wrap-formats))))