3

我想让 OpenID 连接在我的小 luminus 项目中工作。我对 luminus/ring/compojure 中的工作流程有点陌生(主要来自 django、flask 和 servlet)。我已经成功重定向到谷歌,所以我从谷歌得到了“代码”,但是我需要在登录用户之前再向谷歌发出一个请求,这个调用需要另一个用户没有参与的回调,所以我需要像承诺一样搁置用户的请求,但我不确定这部分在 compojure 中是如何工作的。

; this is my code that redirects them to Google, where they accept
(defn login [params] 
  (let [google-oauth2-client-id (System/getenv "GOOGLE_OAUTH2_CLIENT_ID")
        base-url "https://accounts.google.com/o/oauth2/auth"
        args {"client_id" google-oauth2-client-id
              "response_type" "code"
              "scope" "openid email"
              "redirect_uri" "http://localhost:3000/oauth2Callback"
              "state" "anti-forgery here"}]

    (assert google-oauth2-client-id "can't find GOOGLE_OAUTH2_CLIENT_ID in environment")

    (redirect (str base-url "?" (make-query-string args)))
    )
)

; this is my code handling Google's first response
(defn oauth2-callback [params]
  ; params has the code to send to Google

  ; here I should send another request to google that comes back to another callback like oauth2-token-callback that processes the request to the user in the current context

  (redirect "/youreloggedin")
)

在此方法结束时,我应该向用户发送一条消息,说明他们已登录,但我需要等到请求返回。这个工作流程在 luminus 中是如何处理的?


解决了。我没有意识到我可以忽略回调参数。

  (client/post "https://www.googleapis.com/oauth2/v3/token"
               {:headers {"X-Api-Version" "2"}
                :content-type :application/x-www-form-urlencoded
                :form-params {:code (params :code)
                              :client_id (System/getenv "GOOGLE_OAUTH2_CLIENT_ID")
                              :client_secret (System/getenv "GOOGLE_OAUTH2_CLIENT_SECRET")
                              :redirect_uri "http://localhost:3000/oauth2Callback" ; ignored
                              :grant_type "authorization_code"
                              }
                :as :auto ; decode the body straight to hash (if possible)
            })
4

1 回答 1

2

根据此处的 Google 用于 Web 服务器的 OAuth2 的文档,该流程包括以下步骤:

  1. 您的应用程序将浏览器重定向到 Google URL;URL 包括指示所请求访问类型的查询参数。
  2. 结果是一个授权码,Google 在查询字符串中将其返回给您的应用程序。
  3. 收到授权代码后,您的应用程序可以将代码(连同客户端 ID 和客户端密码)交换为访问令牌,在某些情况下,还可以交换刷新令牌。

如果我正确理解了您的问题,则第 3 步不一定涉及对您的服务器的回调,您只需使用 HTTP 客户端向 Google 执行请求即可。我最近在这个项目中为 GitHub 实现了 OAuth2 ,第 3 步在这个函数中实现:

(defn callback
  "Handles the callback from GitHub OAuth flow."
  [code]
  (let [params {:form-params {:client_id client-id
                              :client_secret client-secret
                              :code code}}
        {:keys [body]} (client/post access-token-url params) ;; This is doing the POST
                                                             ;; request to GitHub.
        token  ((qs-map body) "access_token")]               ;; Getting the token from 
                                                             ;; the response here. 
    {:status 302
     :headers {"location" "/repos"
               "set-cookie" (str "token=" token ";Path=/")}}))

我使用clj-http作为 HTTP 客户端,但任何其他都可以。

于 2014-12-08T00:31:41.040 回答