Как аутентифицировать подмножество маршрутов в кольцевом приложении?

У меня есть два набора маршрутов compojure: общедоступные, для которых не требуется аутентификация, и частные, для которых требуется аутентификация. .

(defroutes public-routes
  (GET "/" [] homepage-handler))

(defroutes private-routes
  (GET "/secrets" [] secrets-handler))

Я создал промежуточное программное обеспечение, которое проверяет, аутентифицирован ли пользователь, и либо продолжает цепочку промежуточного программного обеспечения, либо поднимает его.

(defn wrap-must-be-authenticated [handler]
  (fn [request]
    (if (authenticated? request)
      (handler request)
      (throw-unauthorized))))

(def app
  (-> private-routes
      (wrap-must-be-authenticated)))

Это отлично работает, все «частные маршруты» требуют аутентификации.

Как мне добавить public-routes, чтобы они были исключены из wrap-must-be-authenticated?

Я считаю, что defroutes возвращает обработчики кольца, поэтому я думаю, что мне нужно сделать что-то вроде:

(-> (wrap-must-be-authenticated private-routes)
     public-routes)

person Kris    schedule 23.02.2018    source источник


Ответы (1)


Один из способов сделать это — поместить несколько определений routes в содержащий routes и обернуть (wrap-routes) соответствующие маршруты в промежуточное ПО для ограничения доступа:

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

Другой пример из проекта, где я использую restrict buddy.auth:

(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))))
person Taylor Wood    schedule 23.02.2018
comment
Спасибо. Что означает #'? - person Kris; 23.02.2018
comment
Это использует var для ваших определений маршрута, что может помочь, если вы хотите отредактировать/перезагрузить код во время работы приложения. Вместо того, чтобы привязывать маршруты к статическому значению, они будут разрешаться из переменной, которая может измениться после запуска приложения. FWIW, вам не нужно добавлять к маршрутам префикс #'. - person Taylor Wood; 23.02.2018
comment
Как написано, вы сначала консультируетесь с частными маршрутами, и они будут генерировать исключение, если пользователь не аутентифицирован. Вы никогда не сможете успешно предоставить неавторизованному пользователю общедоступную страницу. - person amalloy; 24.02.2018
comment
@amalloy Я использую ту же настройку в приложении Compojure, и она отлично работает для авторизованных маршрутов и других целей. Однако я использую функцию промежуточного программного обеспечения, отличную от OP, которая возвращает {:status 401} вместо броска. - person Taylor Wood; 24.02.2018
comment
Я не уверен, почему, но первый пример работает, даже когда вызывается throw-unauthorized. Я только предполагаю, но это может иметь какое-то отношение к некоторому промежуточному программному обеспечению кольца, которое фиксирует исключения, когда ключ ::type может быть сопоставлен со статусом HTTP. - person Kris; 05.03.2018