15

在我的机器上遇到了一些SSL 问题后,我仍在尝试通过 Google Ruby Client API 访问用户的 Blogger 帐户。我正在使用以下内容:

  • 导轨 3.2.3
  • 红宝石 1.9.3
  • oauth2 (0.8.0)
  • 全域认证 (1.1.1)
  • omn​​iauth-google-oauth2 (0.1.13)
  • 谷歌 api 客户端 (0.4.6)

我可以在验证时通过 Google API 成功验证用户并访问他们的博客。当用户登录时,我存储access_tokenrefresh_token从 Google 收到。一切都很好,直到access_token到期。我正在尝试构建将 替换refresh_token为新的功能access_token,但不断遇到墙壁。以客户端文档为例,这是我正在使用的代码:

  client = Google::APIClient.new
  token_pair = auth.oauth_token   # access_token and refresh_token received during authentication

  # Load the access token if it's available
  if token_pair  
    client.authorization.update_token!(token_pair.to_hash)
  end            

  # Update access token if expired
  if client.authorization.refresh_token && client.authorization.expired?
    client.authorization.fetch_access_token!
  end

  blogger = client.discovered_api('blogger', 'v3')
  result = client.execute(
      api_method: blogger.blogs.list_by_user,
      parameters: {'userId' => "self", 'fields' => 'items(description,id,name,url)'},
      headers: {'Content-Type' => 'application/json'})

此代码在access_token有效时完美运行。但是,一旦到期,我就会看到两个问题:

  1. 即使我知道令牌已过期(我已经检查expires_at了数据库中的值),client.authorization.expired?返回false- 除了使用数据库中的值之外,还有其他方法可以检查令牌的过期吗?
  2. 当我强制执行时,client.authorization.fetch_access_token!我得到一个invalid_request错误。

有人可以告诉我如何使用客户端 APIrefresh_token换新的吗?access_token即使你知道如何用另一种语言来做,那也会有很大的帮助,因为我可以尝试 Rubyfy 它。谢谢!!

4

3 回答 3

26

您可能已经找到了这个,但您可以在 google 上阅读整个过程:https ://developers.google.com/accounts/docs/OAuth2WebServer

omn​​iauth-google-oauth2 策略已经负责设置 access_type 和approval_prompt 因此获取刷新令牌只需使用grant_type=request_token发布到https://accounts.google.com/o/oauth2/token

这里大致是我使用的代码:

def refresh_token
  data = {
    :client_id => GOOGLE_KEY,
    :client_secret => GOOGLE_SECRET,
    :refresh_token => REFRESH_TOKEN,
    :grant_type => "refresh_token"
  }
  @response = ActiveSupport::JSON.decode(RestClient.post "https://accounts.google.com/o/oauth2/token", data)
  if @response["access_token"].present?
    # Save your token
  else
    # No Token
  end
rescue RestClient::BadRequest => e
  # Bad request
rescue
  # Something else bad happened
end
于 2012-09-24T23:37:56.513 回答
16

既然您使用的是 Ruby Google API 客户端,为什么不使用它来交换刷新令牌呢?Ruby API 在内部做了几乎相同的事情,@brimil01 在他的回答中说过。

这就是我使用 Ruby API 将刷新令牌交换为新访问令牌的方式。

def self.exchange_refresh_token( refresh_token )
  client = Google::APIClient.new
  client.authorization.client_id = CLIENT_ID
  client.authorization.client_secret = CLIENT_SECRET
  client.authorization.grant_type = 'refresh_token'
  client.authorization.refresh_token = refresh_token

  client.authorization.fetch_access_token!
  client.authorization
end

并且根据这里的这个问题,建议不要使用该expired?方法来检查访问令牌是否已过期。

基本上,不叫过期了?方法。基本上有零个场景,这是一个好主意。它根本不会为您提供可靠的到期信息。这更像是一个提示,而不是真正的过期时间戳,并且令牌服务器可能会决定在某些理论上但重要的情况下无论如何都要兑现过期的令牌。如果您确实收到无效授权错误,请始终刷新您的访问令牌并重试一次。如果您仍然收到错误,请提出错误。

这就是我所做的。

# Retrieved stored credentials for the provided user email address.
#
# @param [String] email_address
#   User's email address.
# @return [Signet::OAuth2::Client]
#  Stored OAuth 2.0 credentials if found, nil otherwise.
def self.get_stored_credentials(email_address)
  hash = Thread.current['google_access_token']
  return nil if hash.blank?

  hash[email_address]
end

##
# Store OAuth 2.0 credentials in the application's database.
#
# @param [String] user_id
#   User's ID.
# @param [Signet::OAuth2::Client] credentials
#   OAuth 2.0 credentials to store.
def self.store_credentials(email_address, credentials)
  Thread.current['google_access_token'] ||= {}
  Thread.current['google_access_token'][email_address] = credentials
end


def self.credentials_expired?( credentials )
  client = Google::APIClient.new
  client.authorization = credentials
  oauth2 = client.discovered_api('oauth2', 'v2')
  result = client.execute!(:api_method => oauth2.userinfo.get)

  (result.status != 200)
end


# @return [Signet::OAuth2::Client]
#  OAuth 2.0 credentials containing an access and refresh token.
def self.get_credentials
  email_address = ''

  # Check if a valid access_token is already available.
  credentials = get_stored_credentials( email_address )
  # If not available, exchange the refresh_token to obtain a new access_token.

  if credentials.blank?
    credentials = exchange_refresh_token(REFRESH_TOKEN)
    store_credentials(email_address, credentials)
  else
    are_credentials_expired = credentials_expired?(credentials)

    if are_credentials_expired
      credentials = exchange_refresh_token(REFRESH_TOKEN)
      store_credentials(email_address, credentials)
    end
  end

  credentials
end
于 2013-11-19T08:08:05.273 回答
0

我用下面的简单代码修复了它。

   def refesh_auth_tooken(refresh_token) 
       client = Google::APIClient.new 
       puts "REFESH TOOKEN"
       client.authorization = client_secrets
       client.authorization.refresh_token = refresh_token

       #puts YAML::dump(client.authorization)

       client.authorization.fetch_access_token!
       return client.authorization

     end 
于 2013-12-12T08:50:46.187 回答