15

Po próbie połączenia się z urządzeniem SSL issues nadal próbuję uzyskać dostęp do konta Bloggera użytkownika za pośrednictwem interfejsu API klienta Ruby. Używam następujący:Railsy Interfejs API klienta Google - nie można wymienić tokena odświeżania tokenu dostępu

  • Rails 3.2.3
  • Ruby 1.9.3
  • OAuth2 (0.8.0)
  • omniauth (1.1.1)
  • omniauth-google-OAuth2 (0.1.13)
  • google-api-client (0.4.6)

mogę pomyślnie uwierzytelniać użytkowników i dostęp do swoich blogów przez google PI w czasie uwierzytelniania. Gdy użytkownik się loguje, przechowuje się dane od Google i otrzymuje access_token i refresh_token. i wszystko działa wspaniale do momentu wygaśnięcia access_token. Próbuję zbudować funkcjonalność, która wymienia numer refresh_token na nowy access_token, ale wciąż pojawia się przeciwko ścianom. Używanie client documentation jako przykład, jest to kod 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 podczas access_token jest prawidłowy. Tak szybko, jak to wygasa jednak widzę 2 problemy:

  1. Choć wiem token straciła ważność (Sprawdziłem expires_at wartości w bazie danych), client.authorization.expired? powraca false - czy istnieje inny sposób Mogę sprawdzić wygaśnięcie tokena oprócz wykorzystania wartości w bazie danych?
  2. Po wymuszeniu wykonania client.authorization.fetch_access_token! pojawia się błąd invalid_request.

Czy ktoś może mi powiedzieć, jak mogę wymienić refresh_token na nowy access_token przy użyciu interfejsu API klienta? Nawet jeśli wiesz, jak to zrobić w innym języku, byłoby to wielką pomocą, ponieważ mogę spróbować Rubyfiego. Dzięki!!

Odpowiedz

25

Można już znaleźć, ale można odczytać przez cały proces tutaj w google: https://developers.google.com/accounts/docs/OAuth2WebServer

Strategia omniauth-google-OAuth2 już dba o ustawienie typ_dostępu i approval_prompt więc coraz token odświeżania tylko kwestia delegowania https://accounts.google.com/o/oauth2/token z grant_type = request_token

Oto grubsza kod 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 
+0

brimil01, jesteś mężczyzną !! Nie wiem nawet, dlaczego to działa, a moje inne próby nawiązywania połączeń HTTP nie, ale przyglądałem się temu przez 12 godzin, więc wymyślę to jutro. Twój kod całkowicie działa i uratowałeś mnie przed potężnym uderzeniem głową, tak bardzo docenionym. – cerrina

+0

dziękuję. próbowałem to rozgryźć na chwilę. –

+0

Wydaje mi się, że otrzymuję to, gdy zamieszczam to: # "invalid_request"}, @response = # , @headers = {"cache-control" => ["brak pamięci podręcznej, brak sklepu, max-age = 0, konieczność ponownej weryfikacji"], "pragma" => ["brak pamięci podręcznej"], "wygasa" => ["Pt, 01 stycznia 1990 00:00:00 GMT"], "date" => ["Środa, 27 marca 2013 08:50:48 GMT"], "typ zawartości" => ["application/json "]," x-content-type-options "=> [" nosniff "]," x-frame-options "=> [" SAMEORIGIN "]," x-xss-protection "=> [" 1; tryb = blok "]," serwer "=> [" GSE "]," połączenie "=> [" zamknij "]}> ... –

16

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

W ten sposób używam interfejsu API Ruby do wymiany mojego tokena 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 

A według this issue here, zaleca się, aby nie używać metody expired? aby sprawdzić, czy token dostęp wygasł.

Zasadniczo nie dzwonisz do nieważnego? metoda. Zasadniczo istnieją scenariusze zero , w których jest to dobry pomysł. Po prostu nie dostarczy Ci wiarygodnych informacji o wygaśnięciu. Jest to raczej wskazówka niż prawdziwy znacznik czasu wygaśnięcia, a serwer tokenów może mimo wszystko zdecydować o honorowaniu wygasłego tokena w pewnych nieco teoretycznych, ale ważnych okolicznościach. Jeśli otrzymasz nieprawidłowy błąd przydziału, zawsze odświeżaj token dostępu i spróbuj raz. Jeśli nadal pojawia się błąd, zwiększ błąd.

Oto, 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 
+1

W' credentials_expired? ', wywołanie' klienta. execute' nie powinien używać formularza 'wykonaj!', ponieważ spowoduje zgłoszenie wyjątku, jeśli poświadczenia wygasną, zamiast wypełniania 'wyniku' o nieautoryzowanym statusie. – pauljm

0

Naprawiłem to 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 
Powiązane problemy