Rails Google Client API-nie można wymienić tokena odświeżania na token dostępu

Po zmaganiu się z pewnymi problemami SSL na moim komputerze, nadal próbuję uzyskać dostęp do konta Bloggera Użytkownika za pośrednictwem interfejsu API klienta Google Ruby. Używam:

  • Rails 3.2.3
  • Ruby 1.9.3
  • oauth2 (0.8.0)
  • omniauth (1.1.1)
  • omniauth-google-OAuth2 (0.1.13)
  • [[19]} google-api-client (0.4.6)

Mogę skutecznie uwierzytelniać użytkowników i uzyskiwać dostęp do ich blogów za pośrednictwem Google API w tym czasie uwierzytelniania. Kiedy użytkownik się loguje, przechowuję access_token i refresh_token, które otrzymuję od Google. i wszystko działa świetnie, dopóki access_token nie wygaśnie. Staram się zbudować funkcjonalność, która zamienia refresh_token na nową access_token, ale ciągle podskakuje na ściany. Korzystając z dokumentacji klienta jako przykład, jest to kod, którego używam:

  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'})

Ten kod działa doskonale, gdy {[1] } jest poprawny. Jak tylko wygaśnie, widzę 2 problemy: {]}

  1. nawet chociaż wiem, że token wygasł (sprawdziłem expires_at wartość w bazie danych), client.authorization.expired? zwraca false -- czy istnieje inny sposób, aby sprawdzić wygaśnięcie tokenu poza użyciem wartości w bazie danych?
  2. kiedy wymuszam wykonanie client.authorization.fetch_access_token! dostaję invalid_request błąd.

Czy ktoś może mi powiedzieć, jak mogę wymienić {[2] } na Nowy access_token za pomocą interfejsu API klienta? Nawet jeśli wiesz, jak to zrobić w innym języku, byłoby to bardzo pomocne, ponieważ mogę spróbować Ruby go. Dzięki!!

Author: Community, 2012-09-25

3 answers

Być może już to znalazłeś, ale możesz przeczytać cały proces tutaj w google: https://developers.google.com/accounts/docs/OAuth2WebServer

Strategia omniauth-google-OAuth2 już zajmuje się ustawianiem access_type i approval_prompt, więc uzyskanie tokena odświeżania jest tylko kwestią wysłania do https://accounts.google.com/o/oauth2/token with grant_type=request_token

Oto mniej więcej Kod, którego używam:

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
 25
Author: brimil01,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-24 23:37:56

Ponieważ używasz klienta Ruby Google API, dlaczego nie użyć go do wymiany tokena odświeżania? API Ruby robi prawie to samo wewnętrznie, co @brimil01 powiedział w swojej odpowiedzi.

W ten sposób używam API Ruby do wymiany tokenu odświeżania na nowy token dostępu.

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

I zgodnie z ten problem tutaj , zaleca się nie używać metody expired? do sprawdzania, czy token dostępu wygasł.

Zasadniczo, nie nazywaj przeterminowane? metoda. Istnieje zasadniczo zero scenariusze, w których to dobry pomysł. Po prostu nie da ci niezawodności informacja o wygaśnięciu. To bardziej podpowiedź niż prawdziwe wydechy znacznik czasu, a serwer tokenu może zdecydować o uznaniu wygasłego tokenu tak czy inaczej, w pewnych teoretycznych, ale ważnych okolicznościach. Jeśli otrzymasz nieprawidłowy błąd przyznania, zawsze odśwież token dostępu i spróbuj jeszcze raz. Jeśli nadal masz błąd, podnieś błąd.

Oto to, co robię.

# 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
 16
Author: Anjan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-19 08:08:05

Naprawiłem go za pomocą prostego kodu poniżej.

   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 
 0
Author: Quang Binh Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-12 08:50:46