Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Authentication 在单页Clojure web应用程序中使用Friend进行身份验证和授权_Authentication_Clojure_Compojure - Fatal编程技术网

Authentication 在单页Clojure web应用程序中使用Friend进行身份验证和授权

Authentication 在单页Clojure web应用程序中使用Friend进行身份验证和授权,authentication,clojure,compojure,Authentication,Clojure,Compojure,我正在尝试将好友身份验证和授权集成到Clojure/Compojure单页web应用程序中 我有一个由Angular控制器支持的登录表单,该控制器使用AJAX对web应用程序的用户名和密码进行身份验证,并获得经过身份验证的用户记录。因此,我不希望使用基于好友表单的登录提供的默认行为-我基本上希望依赖HTTP状态码,并且不希望任何好友页面重定向 例如,发出未经验证的请求只应返回401状态代码,而不应重定向到“/login”。我在配置Friend时通过指定一个自定义的“:unauthenticate

我正在尝试将好友身份验证和授权集成到Clojure/Compojure单页web应用程序中

我有一个由Angular控制器支持的登录表单,该控制器使用AJAX对web应用程序的用户名和密码进行身份验证,并获得经过身份验证的用户记录。因此,我不希望使用基于好友表单的登录提供的默认行为-我基本上希望依赖HTTP状态码,并且不希望任何好友页面重定向

例如,发出未经验证的请求只应返回401状态代码,而不应重定向到“/login”。我在配置Friend时通过指定一个自定义的“:unauthenticated handler”(下面包含的代码)来实现这一部分

在成功登录时,我只需要一个200状态码,而不是重定向到最初请求的页面。这就是我无法工作的地方

我根据各种示例编写了一个自定义朋友身份验证工作流(我的Clojure技能目前处于初级阶段):

这是我声明了中间件的处理程序:

(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))))
这基本上是有效的,几乎做了我需要的一切

因为“makeauth”中的“redirect on auth?”为true,所以在成功登录时会生成一个页面重定向-我想阻止该重定向,所以我将该值设置为false。但是,这一更改会导致404和登录失败

因此,除了朋友身份验证映射之外,我还需要在这里返回一个200状态码,并且我还希望返回响应正文中的“用户记录”,以便客户端应用程序可以根据用户角色定制UI(我已经包装好JSON请求/响应并开始工作)

因此,我认为在调用Friend“make auth”函数时需要与此等效的函数:

{:status 200 :body user-record}
但是,我似乎可以拥有身份验证映射或响应,但不能同时拥有两者


这可以通过Friend实现吗?如果可以,如何实现?

您需要将
:auth上的重定向设置为
false
,并且需要将您的响应包装在响应图中
{:status 200:body(工作流/进行身份验证…}
。请注意,您可能需要将身体序列化为
字符串或其他可以处理的内容。

我已经为您的问题构建了一个有效的解决方案。关键是确保返回状态、正文,并将身份验证凭据合并到响应中。你想回来吗

{:status 200 :body {:message "Hello World"} 
 :session {:cemerick.friend/identity {...}} ...}
上述解决方案的问题在于,它将会话结果合并到主体中,而不是环响应本身


乍一看,这似乎奏效了,但尽管它确实将用户记录作为JSON和200状态码正确地返回给客户机,但仍然没有创建经过身份验证的会话。当我试图访问受保护的资源时,它失败了。@caprica,听到这个消息很抱歉。您能否提供更多的代码作为示例?我对您的中间件特别感兴趣。@caprica,您是否可以尝试删除
会话/wrap session
处理程序/site
已经在会话中包装您的处理程序,这可能会导致您的问题。删除会话/wrap session没有任何区别-我在随后访问经过身份验证的链接时仍然失败。事实上,我只添加了session/wrap session,以便在事情不起作用时尝试一些东西。由于其他答案中提到的bug或缺少功能/行为,它不起作用。在我自己的应用程序中,我通过让初始客户端AJAX请求在成功身份验证时忽略页面重定向,然后发出后续请求以获取角色来伪造它。不是很理想,但它可以工作。也许这是相关的:,这意味着目前不可能,需要修复朋友。是的,似乎是这样。
{:status 200 :body {:message "Hello World"} 
 :session {:cemerick.friend/identity {...}} ...}
(defn- form-ajax-response 
  "Creates an Ajax Request.
   Authenticates User by merging authentication
   into response along with status and body allowing
   for ajax response."
  [status body resp auth content-type]
  (let [auth-resp (friend/merge-authentication (dissoc resp :body-params) auth)
        formatter (case content-type 
                    "application/edn" noir.response/edn
                    noir.response/json)]
    (merge auth-resp {:status status} (formatter {:body body}))))

(def not-nil? (complement nil?))

(defn form-or-ajax-login 
  "Friend Workflow for Handling forms or ajax requests posted to 
   '/login'.  When a form is posted, the request will initiate a redirect
   on login When the post is performed via ajax. A response will be sent
   with success and redirect information"
  [& {:keys [login-uri credential-fn login-failure-handler redirect-on-auth?] :as ajax-config
      :or {redirect-on-auth? true}}]
  (fn [{:keys [uri request-method content-type params] :as request}]
    (when (and (= :post request-method)
               (= uri (gets :login-uri ajax-config (::friend/auth-config request))))
      (let [creds {:username (:username params) 
                   :password (:password params)}
            {:keys [username password]} creds
            ajax? (not-nil? (ajax-request-type content-type))
            cred-fn (gets :credential-fn ajax-config (::friend/auth-config request))]
        (when-let [user-record (and username password (cred-fn creds))]
          (let [user-auth (workflow/make-auth user-record {::friend/workflow :form-or-ajax
                                                           ::friend/redirect-on-auth? false})]
            (case ajax?
              true (form-ajax-response 202 {:Tom "Peterman"} request user-auth content-type)
              user-auth)))))))