简体   繁体   English

Rails 4-带有omniauth-google-oauth2的Google一次性代码流,不断获取“无效代码”

[英]Rails 4 - Google One Time Code Flow with omniauth-google-oauth2, keep getting “Invalid code”

I have a Rails app in which I want users to be able to sign in / up with Google. 我有一个Rails应用程序,我希望用户能够在其中登录/注册Google。 I'm using the following gem: 我正在使用以下宝石:

#gemfile
gem 'omniauth-google-oauth2'

I've almost got it to work (I actually received the access token once, not sure why) - but before getting the access_token I constantly get the following error: 我几乎可以正常工作了(我实际上只收到一次访问令牌,不知道为什么)-但是在获取access_token之前,我经常遇到以下错误:

"error"=>"invalid_grant", "error_description"=>"Invalid code."

I have checked so that the code is unique for each request and that it isn't nil. 我已经检查过了,以便每个请求的代码都是唯一的,并且它不是nil。 The relevant parts of the method where I try to get the access_token after I've received the one time authorisation code looks like this: 收到一次性授权代码后,我尝试获取access_token的方法的相关部分如下所示:

def google_authentication
  respond_to do |format|
    # authorisation code

    code = params[:code]
    unless code.blank?

      client_id = ENV["GOOGLE_CLIENT_ID"]
      client_secret = ENV["GOOGLE_CLIENT_SECRET"]
      redirect_uri = 'postmessage'
      grant_type = 'authorization_code'

      load = {client_id: client_id, client_secret: client_secret,  redirect_uri: redirect_uri, grant_type: grant_type, code: code}
      payload = load.to_json
      url = "https://www.googleapis.com/oauth2/v3/token"
      response = HTTParty.post(url, :query => load)

      json = JSON.parse(response.body)

      unless json.nil?
        unless json[:error].present?
          # TODO: Handle data      
          format.json { render :json => {:message => "Success"} }              
        else
          # ERROR "Invalid code" always happen
        end
      end
    end
  end
end

In Google's developer console I have the following credentials: 在Google开发人员控制台中,我具有以下凭据:

Client ID           [CLient ID]
Email address       [Email]
Client secret       [Secret]
Redirect URIs       http://127.0.0.1:3000/
JavaScript origins  http://127.0.0.1:3000

Would be thankful for any ideas or tips. 感谢任何想法或技巧。

Update for completion 更新完成

This is how I set up omniauth-google-oauth2: 这是我设置omniauth-google-oauth2的方法:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"],  ENV["GOOGLE_CLIENT_SECRET"],
    {
      :scope => "email, profile",
      :prompt => "select_account",
      :provider_ignores_state => true
    }
end

Update 2 更新2

As mentioned above I once managed to get the access token once, I managed to reproduce it again. 如上所述,我曾经设法获得访问令牌一次,然后又设法重现了它。 I did it by clicking my sign in button three times.The first time I got: 我通过单击登录按钮三次来做到这一点。

"error"=>"invalid_grant", "error_description"=>"Invalid code."

The second click resulted in: 第二次点击导致:

"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."

And the third time I successfully got the access_token . 第三次,我成功获取了access_token I find it really strange that I sometimes get the access_token , but most of the time get: 我有时有时会获得access_token ,这真的很奇怪,但是大多数时候都会得到:

"error"=>"invalid_grant", "error_description"=>"Invalid code."

And the success / error "rate" isn't 100% consistent. 而且成功/错误的“比率”不是100%一致的。 Sometimes it takes more than three clicks. 有时需要超过三下单击。 I find it quite strange that it sometimes works and that I sometimes get different error responses without changing anything in my code. 我感到很奇怪,它有时可以工作,有时会得到不同的错误响应,而无需更改代码中的任何内容。

Could it be related to time / expiration date of the code? 可能与代码的时间/到期日期有关吗?

Update 3 更新3

For additional completion. 额外完成。 This is how my Javascript (or CoffeeScript) looks like when the user clicks the Google Sign in button: 这是用户单击Google登录按钮时我的Javascript(或Cof​​feeScript)的样子:

$(document).ready ->
  $.ajax
    url: 'https://apis.google.com/js/client:plus.js?onload=gpAsyncInit'
    dataType: 'script'
    cache: true


window.gpAsyncInit = ->
  $('.googleplus-login').click (e) ->
    e.preventDefault()
    gapi.auth.authorize {
      immediate: false
      response_type: 'code'
      cookie_policy: 'single_host_origin'
      client_id: '[id]'
      scope: 'email profile'
    }, (response) ->
      if response and !response.error

        jQuery.ajax
          type: 'POST'
          url: '/auth/google_oauth2/callback'
          dataType: 'json'
          data: response
          success: (json) ->
            # response from server
            console.log "JSON: " + json
            return
      else
        # google authentication failed

I cant help with the ruby part but I may be able to help you figure out what's wrong. 对于红宝石部分,我无法解决,但也许可以帮助您找出问题所在。

There are in fact 3 codes returned by Google's authentication server. 实际上,Google的身份验证服务器返回了3个代码。 Authorization code, Access token, and refresh token. 授权代码,访问令牌和刷新令牌。

  • Authorization code can only be used once to get the first refresh token. 授权代码只能使用一次才能获得第一个刷新令牌。
  • Access Token used to access data on the apis, expires after an hour. 用于访问api上数据的访问令牌会在一个小时后过期。
  • Refresh Token used to get a new access token when it expires. 刷新令牌,用于在过期时获取新的访问令牌。 good until the user removes access. 直到用户删除访问权限为止。

Authorization code 授权码

This is the code that gets returned when the user hits accept to your application. 这是当用户点击接受您的应用程序时返回的代码。

Example: 例:

Change the client id, secret, and scope in this URI to the ones you are using. 将此URI中的客户端ID,密码和范围更改为您正在使用的客户端ID,密码和范围。 then paste it into a browser location bar. 然后将其粘贴到浏览器位置栏中。

https://accounts.google.com/o/oauth2/auth?client_id={clientid}.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope={scope}&response_type=code

在此处输入图片说明

It will prompt you for authentication. 它将提示您进行身份验证。 If you click except you get another window with a long code in it looking something like this. 如果单击,则会出现另一个带有长代码的窗口,看起来像这样。

在此处输入图片说明

That is the Authentication code, its only purpose in life is for you to use it to get an access token and a refresh token. 这就是身份验证代码,其唯一的目的就是让您使用它来获取访问令牌和刷新令牌。 It can only be used once , and its probably short lived though I have never tested how long they are good for. 它只能使用一次 ,虽然我从未测试过它们适合使用多长时间,但它可能寿命很短。

In the uri above Note: the response type code. 在上面的uri中注意:响应类型代码。

Exchange: 交换:

Once you have that authentication code you need to exchange it for an access token and a refresh token. 获得该验证码后,您需要将其交换为访问令牌和刷新令牌。 this is a HTTP POST so cant be placed in a browser window. 这是HTTP POST,因此不能放在浏览器窗口中。

https://accounts.google.com/o/oauth2/token
code=4/X9lG6uWd8-MMJPElWggHZRzyFKtp.QubAT_P-GEwePvB8fYmgkJzntDnaiAI&client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code

Note: grant_type=authorization_code this tells the server you are sending it an authorization code. 注意:grant_type = authorization_code告诉服务器您正在向其发送授权码。

response 响应

{
"access_token" : "ya29.1.AADtN_VSBMC2Ga2lhxsTKjVQ_ROco8VbD6h01aj4PcKHLm6qvHbNtn-_BIzXMw",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/J-3zPA8XR1o_cXebV9sDKn_f5MTqaFhKFxH-3PUPiJ4"
}

You now have an access token that can be used to access the Google APIs, it is short live lasts only 3600 seconds or 1 hour. 现在,您有了一个可用于访问Google API的访问令牌,该令牌的寿命很短,仅持续3600秒或1个小时。 After that you must use the refresh token to get access again. 之后,您必须使用刷新令牌才能再次访问。

Use refreshtoken 使用refreshtoken

https://accounts.google.com/o/oauth2/token
client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token

response 响应

{
"access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ",
"token_type" : "Bearer",
"expires_in" : 3600
}

Now that you understand all of that 现在您已经了解了所有这些

"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."

means that you are sending the authorization code again you can only use it once you should be sending the refresh token again. 表示您要再次发送授权码,则只能在应该再次发送刷新令牌时使用它。 There is something up with your authentication flow. 您的身份验证流程有问题。 Again sorry I cant help with the ruby part. 再次抱歉,我无法帮助红宝石部分。

code ripped from Google 3 legged oauth2 flow 代码从Google 3的oauth2流中剥离出来

So ...as it is wrote: 因此...如其写道:

Authorized redirect URIs One URI per line. 授权的重定向URI每行一个URI。 Needs to have a protocol, no URL fragments, and no relative paths. 需要具有协议,没有URL片段和相对路径。 Can't be a public IP Address. 不能是公共IP地址。

Your setting: 您的设置:

Redirect URIs http://127.0.0.1:3000/ JavaScript origins http://127.0.0.1:3000/ 重定向URI http://127.0.0.1:3000/ JavaScript起源http://127.0.0.1:3000/

...is wrong. ...是错的。

It should be: 它应该是:

Redirect URIs: http://my.true.domain/users/auth/google/callback 重定向URI: http://my.true.domain/users/auth/google/callback

and

 provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"],  ENV["GOOGLE_CLIENT_SECRET"],
    {
      :scope => "email, profile",
      :name => "google",
      ...

I hope it help! 希望对您有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Rails,使用omniauth-google-oauth2获取circledByCount - Rails, get circledByCount with omniauth-google-oauth2 在 rails API 中使用 omniauth-google-oauth2 - Using omniauth-google-oauth2 in rails API omniauth-google-oauth2 日历同步提供无效凭据 - omniauth-google-oauth2 calendar sync giving invalid credential 使用omniauth-google-oauth2图片大小的Rails设计不起作用 - Rails devise with omniauth-google-oauth2 image size does not work 在Rails 2.3.8和ruby 1.8.7中使用omniauth-google-oauth2 gem - Using omniauth-google-oauth2 gem in rails 2.3.8 and ruby 1.8.7 如何在Rails中使用具有增量授权的omniauth-google-oauth2 gem? - How to use omniauth-google-oauth2 gem with incremental authorization in Rails? devise + omniauth-google-oauth2调用错误 - devise + omniauth-google-oauth2 calling errors 使用omniauth-google-oauth2 gem进行设计 - Devise with omniauth-google-oauth2 gem 使用MiniTest,当尝试测试“ omniauth-google-oauth2” gem时,我一直收到302重定向到我的sign_in路径 - Using MiniTest, when trying to test `omniauth-google-oauth2` gem I keep getting a 302 redirect to my sign_in path Google Oauth使用omniauth-google-oauth2登录失败 - Google Oauth Login with omniauth-google-oauth2 failed frequently
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM