Я пытаюсь интегрировать аутентификацию и авторизацию Friend в одностраничное веб-приложение Clojure/Compojure.
У меня есть форма входа, поддерживаемая контроллером Angular, и этот контроллер использует AJAX для аутентификации имени пользователя и пароля в веб-приложении и получения аутентифицированной записи пользователя. Из-за этого мне не нужно поведение по умолчанию, обеспечиваемое входом в систему на основе формы Friend — я в основном хочу полагаться на коды состояния HTTP и мне не нужны какие-либо перенаправления страниц Friend.
Например, выполнение неаутентифицированного запроса должно просто возвращать код состояния 401 и не должно перенаправлять на «/login». У меня эта часть работает, указав пользовательский «: unauthenticated-handler» при настройке Friend (код приведен ниже).
При успешном входе мне просто нужен код состояния 200, а не перенаправление на первоначально запрошенную страницу. Это то, что я не могу заставить работать.
Я написал собственный рабочий процесс аутентификации Friend на основе различных примеров (мои навыки работы с Clojure сейчас находятся на уровне новичка):
(defn my-auth
[& {:keys [credential-fn]}]
(routes
(GET "/logout" req
(friend/logout* {:status 200}))
(POST "/login" {{:keys [username password]} :params}
(if-let [user-record (-> username credential-fn)]
(if
(and
[user-record password]
(creds/bcrypt-verify password (:password user-record)))
(let [user-record (dissoc user-record :password)]
(workflows/make-auth user-record {:cemerick.friend/workflow :my-auth :cemerick.friend/redirect-on-auth? true}))
{:status 401})
{:status 401}))))
Вот мой обработчик с объявленным промежуточным программным обеспечением:
(def app
(->
(handler/site
(friend/authenticate app-routes
{:credential-fn (partial creds/bcrypt-credential-fn my-credential-fn)
:unauthenticated-handler unauthenticated
:workflows [(my-auth :credential-fn my-credential-fn)]}))
(session/wrap-session)
(params/wrap-keyword-params)
(json/wrap-json-body)
(json/wrap-json-response {:pretty true})))
И дополнительная функция обработчика, на которую ссылается выше:
(defn unauthenticated [v]
{:status 401 :body "Unauthenticated"})
Наконец, дополнительный фрагмент маршрутов для проверки аутентификации:
(GET "/auth" req
(friend/authenticated (str "You have successfully authenticated as "
(friend/current-authentication))))
Это в основном работает и почти делает все, что мне нужно.
Потому что "перенаправление при аутентификации?" верно в «make-auth», при успешном входе в систему создается перенаправление страницы — я хочу предотвратить это перенаправление, поэтому я установил значение false. Однако это единственное изменение приводит к ошибке 404 и неудачному входу в систему.
Таким образом, помимо карты аутентификации Friend, мне нужно каким-то образом вернуть здесь код состояния 200, а также я хочу вернуть «запись пользователя» в теле ответа, чтобы клиентское приложение могло адаптировать пользовательский интерфейс в зависимости от роли пользователя (я уже есть запросы/ответы JSON, упакованные и работающие).
Поэтому я думаю, что мне нужен эквивалент этого, когда я вызываю функцию Friend "make-auth":
{:status 200 :body user-record}
Однако похоже, что у меня может быть либо карта аутентификации, либо ответ, но не оба вместе.
Можно ли этого добиться с помощью Friend, и если да, то как?