Rails 4 - Google 使用 omniauth-google-oauth2 的一次性代码流,继续获取 "Invalid code"
Rails 4 - Google One Time Code Flow with omniauth-google-oauth2, keep getting "Invalid code"
我有一个 Rails 应用程序,我希望用户能够在其中使用 Google 登录/注册。我正在使用以下 gem:
#gemfile
gem 'omniauth-google-oauth2'
我几乎已经开始工作了(我实际上收到了一次访问令牌,不知道为什么)- 但在获得 access_token 之前,我经常收到以下错误:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
我已经检查过每个请求的代码都是唯一的,并且它不是零。在我收到一次性授权代码后尝试获取 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
在 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
如有任何想法或提示,我们将不胜感激。
完成更新
这就是我设置 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
更新 2
如上所述,我曾经设法获得一次访问令牌,我设法再次复制它。我第一次点击我的登录按钮三 times.The 做到了:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
第二次点击导致:
"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."
而第三次我成功拿到了access_token
。我觉得很奇怪,我有时会得到 access_token
,但大多数时候会得到:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
并且成功/错误 "rate" 并非 100% 一致。有时需要点击三下以上。我觉得很奇怪,它有时会起作用,有时我会在不更改代码任何内容的情况下得到不同的错误响应。
会不会和代码的时间/有效期有关?
更新 3
额外完成。这就是当用户单击 Google 登录按钮时我的 Javascript(或 CoffeeScript)的样子:
$(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
我无法在 ruby 部分提供帮助,但我可以帮助您找出问题所在。
实际上 Google 的验证服务器返回了 3 个代码。授权码、访问令牌和刷新令牌。
- 授权码只能使用一次获取第一个刷新令牌
- 访问令牌 用于访问 API 上的数据,一小时后过期。
- 刷新令牌 用于在过期时获取新的访问令牌。好,直到用户删除访问。
授权码
这是当用户点击接受您的应用程序时返回的代码。
示例:
将此 URI 中的客户端 ID、机密和范围更改为您正在使用的。然后将其粘贴到浏览器地址栏中。
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
它会提示您进行身份验证。如果你点击除了你会得到另一个 window 里面有一个长代码看起来像这样。
那是验证码,它在生活中的唯一目的就是让你用它来获取访问令牌和刷新令牌。它只能使用一次,而且它的寿命可能很短,但我从未测试过它们的有效期。
在上面的uri中注意:响应类型代码。
交易所:
获得验证码后,您需要将其交换为访问令牌和刷新令牌。这是一个 HTTP POST,所以不能放在浏览器中 window。
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
注意:grant_type=authorization_code 这会告诉服务器您正在向它发送授权码。
响应
{
"access_token" : "ya29.1.AADtN_VSBMC2Ga2lhxsTKjVQ_ROco8VbD6h01aj4PcKHLm6qvHbNtn-_BIzXMw",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/J-3zPA8XR1o_cXebV9sDKn_f5MTqaFhKFxH-3PUPiJ4"
}
您现在拥有可用于访问 Google API 的访问令牌,它的有效期很短,仅持续 3600 秒或 1 小时。之后,您必须使用刷新令牌再次获得访问权限。
使用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
回应
{
"access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ",
"token_type" : "Bearer",
"expires_in" : 3600
}
现在你明白了所有这些
"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."
表示您再次发送授权码,您只能在应该再次发送刷新令牌时使用它。您的身份验证流程有问题。再次抱歉,我无法帮助 ruby 部分。
中窃取的代码
所以...如上所写:
Authorized redirect
URIs One URI per line. Needs to have a protocol,
no URL fragments, and no relative paths. Can't be a public IP Address.
您的设置:
Redirect URIs http://127.0.0.1:3000/
JavaScript origins http://127.0.0.1:3000/
...错了。
应该是:
Redirect URIs: http://my.true.domain/users/auth/google/callback
和
provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
{
:scope => "email, profile",
:name => "google",
...
希望对您有所帮助!
我有一个 Rails 应用程序,我希望用户能够在其中使用 Google 登录/注册。我正在使用以下 gem:
#gemfile
gem 'omniauth-google-oauth2'
我几乎已经开始工作了(我实际上收到了一次访问令牌,不知道为什么)- 但在获得 access_token 之前,我经常收到以下错误:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
我已经检查过每个请求的代码都是唯一的,并且它不是零。在我收到一次性授权代码后尝试获取 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
在 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
如有任何想法或提示,我们将不胜感激。
完成更新
这就是我设置 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
更新 2
如上所述,我曾经设法获得一次访问令牌,我设法再次复制它。我第一次点击我的登录按钮三 times.The 做到了:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
第二次点击导致:
"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."
而第三次我成功拿到了access_token
。我觉得很奇怪,我有时会得到 access_token
,但大多数时候会得到:
"error"=>"invalid_grant", "error_description"=>"Invalid code."
并且成功/错误 "rate" 并非 100% 一致。有时需要点击三下以上。我觉得很奇怪,它有时会起作用,有时我会在不更改代码任何内容的情况下得到不同的错误响应。
会不会和代码的时间/有效期有关?
更新 3
额外完成。这就是当用户单击 Google 登录按钮时我的 Javascript(或 CoffeeScript)的样子:
$(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
我无法在 ruby 部分提供帮助,但我可以帮助您找出问题所在。
实际上 Google 的验证服务器返回了 3 个代码。授权码、访问令牌和刷新令牌。
- 授权码只能使用一次获取第一个刷新令牌
- 访问令牌 用于访问 API 上的数据,一小时后过期。
- 刷新令牌 用于在过期时获取新的访问令牌。好,直到用户删除访问。
授权码
这是当用户点击接受您的应用程序时返回的代码。
示例:
将此 URI 中的客户端 ID、机密和范围更改为您正在使用的。然后将其粘贴到浏览器地址栏中。
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
它会提示您进行身份验证。如果你点击除了你会得到另一个 window 里面有一个长代码看起来像这样。
那是验证码,它在生活中的唯一目的就是让你用它来获取访问令牌和刷新令牌。它只能使用一次,而且它的寿命可能很短,但我从未测试过它们的有效期。
在上面的uri中注意:响应类型代码。
交易所:
获得验证码后,您需要将其交换为访问令牌和刷新令牌。这是一个 HTTP POST,所以不能放在浏览器中 window。
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
注意:grant_type=authorization_code 这会告诉服务器您正在向它发送授权码。
响应
{
"access_token" : "ya29.1.AADtN_VSBMC2Ga2lhxsTKjVQ_ROco8VbD6h01aj4PcKHLm6qvHbNtn-_BIzXMw",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/J-3zPA8XR1o_cXebV9sDKn_f5MTqaFhKFxH-3PUPiJ4"
}
您现在拥有可用于访问 Google API 的访问令牌,它的有效期很短,仅持续 3600 秒或 1 小时。之后,您必须使用刷新令牌再次获得访问权限。
使用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
回应
{
"access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ",
"token_type" : "Bearer",
"expires_in" : 3600
}
现在你明白了所有这些
"error"=>"invalid_grant", "error_description"=>"Code was already redeemed."
表示您再次发送授权码,您只能在应该再次发送刷新令牌时使用它。您的身份验证流程有问题。再次抱歉,我无法帮助 ruby 部分。
中窃取的代码所以...如上所写:
Authorized redirect URIs One URI per line. Needs to have a protocol, no URL fragments, and no relative paths. Can't be a public IP Address.
您的设置:
Redirect URIs http://127.0.0.1:3000/ JavaScript origins http://127.0.0.1:3000/
...错了。
应该是:
Redirect URIs: http://my.true.domain/users/auth/google/callback
和
provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
{
:scope => "email, profile",
:name => "google",
...
希望对您有所帮助!