web-dev-qa-db-de.com

Aktualisieren Sie das Token mit Omniauth-oauth2 in der Rails-Anwendung

Ich benutze omniauth-oauth2 in Rails, um mich bei einer Site zu authentifizieren, die oauth2 unterstützt. Nach dem oauth dance gibt mir die Seite folgendes, was ich in der Datenbank festhalte:

  1. Zugangstoken
  2. Expires_AT (Ticks)
  3. Token aktualisieren

Gibt es eine Omniauth-Methode, um das Token nach Ablauf automatisch zu aktualisieren, oder sollte ich benutzerdefinierten Code schreiben, der dasselbe tut? 

Wenn benutzerdefinierter Code geschrieben werden soll, ist ein Helfer der richtige Ort, um die Logik zu schreiben?

25
ganeshran

Omniauth bietet diese Funktionalität nicht direkt an, daher habe ich die vorherige Antwort und eine andere SO Antwort verwendet, um den Code in mein Modell zu schreiben. User.rb

def refresh_token_if_expired
  if token_expired?
    response    = RestClient.post "#{ENV['DOMAIN']}oauth2/token", :grant_type => 'refresh_token', :refresh_token => self.refresh_token, :client_id => ENV['APP_ID'], :client_secret => ENV['APP_SECRET'] 
    refreshhash = JSON.parse(response.body)

    token_will_change!
    expiresat_will_change!

    self.token     = refreshhash['access_token']
    self.expiresat = DateTime.now + refreshhash["expires_in"].to_i.seconds

    self.save
    puts 'Saved'
  end
end

def token_expired?
  expiry = Time.at(self.expiresat) 
  return true if expiry < Time.now # expired token, so we should quickly return
  token_expires_at = expiry
  save if changed?
  false # token not expired. :D
end

Bevor Sie den API-Aufruf mithilfe des Zugriffstokens durchführen, können Sie die Methode wie folgt aufrufen, wobei current_user der angemeldete Benutzer ist.

current_user.refresh_token_if_expired

Stellen Sie sicher, dass Sie den rest-client gem installieren, und fügen Sie in der Modelldatei die Anforderungsdirektive require 'rest-client' hinzu. ENV['DOMAIN'], ENV['APP_ID'] und ENV['APP_SECRET'] sind Umgebungsvariablen, die in config/environments/production.rb (oder in Entwicklung) festgelegt werden können.

19
ganeshran

Tatsächlich verfügen die omniauth-oauth2 gem und ihre Abhängigkeit oauth2 über eine eingebaute Refresh-Logik.

Siehe unter https://github.com/intridea/oauth2/blob/master/lib/oauth2/access_token.rb#L80

# Refreshes the current Access Token
#
# @return [AccessToken] a new AccessToken
# @note options should be carried over to the new AccessToken
def refresh!(params = {})
  fail('A refresh_token is not available') unless refresh_token
  params.merge!(:client_id      => @client.id,
                :client_secret  => @client.secret,
                :grant_type     => 'refresh_token',
                :refresh_token  => refresh_token)
  new_token = @client.get_token(params)
  new_token.options = options
  new_token.refresh_token = refresh_token unless new_token.refresh_token
  new_token
end

Und in https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L74 :

self.access_token = access_token.refresh! if access_token.expired?

Sie können es also vielleicht nicht direkt mit omniauth-oauth2 tun, aber Sie können mit oauth2 sicherlich etwas Ähnliches tun:

client = strategy.client # from your omniauth oauth2 strategy
token = OAuth2::AccessToken.from_hash client, record.to_hash
# or
token = OAuth2::AccessToken.new client, token, {expires_at: 123456789, refresh_token: "123"}
token.refresh!
17
Eero

Eeros Antwort eröffnete mir einen Weg, um das zu lösen. Ich habe ein Helferanliegen für meine Klassen, die mir einen GmailService besorgen. Im Rahmen dieses Prozesses wird das Benutzerobjekt (das die Google-Auth-Informationen enthält) geprüft, ob es abgelaufen ist. Wenn ja, wird es vor dem Zurückkehren des Dienstes aktualisiert.

def gmail_service(user)
  mail = Google::Apis::GmailV1::GmailService.new

  # Is the users token expired?
  if user.google_token_expire.to_datetime.past?
    oauth = OmniAuth::Strategies::GoogleOauth2.new(
      nil, # App - nil seems to be ok?!
      "XXXXXXXXXX.apps.googleusercontent.com", # Client ID
      "ABC123456" # Client Secret
    )
    token = OAuth2::AccessToken.new(
      oauth.client,
      user.google_access_token,
      { refresh_token: user.google_refresh_token }
    )
    new_token = token.refresh!

    if new_token.present?
      user.update(
        google_access_token: new_token.token,
        google_token_expire: Time.at(new_token.expires_at),
        google_refresh_token: new_token.refresh_token
      )
    else
      puts("DAMN - DIDN'T WORK!")
    end
  end

  mail.authorization = user.google_access_token

  mail
end
6
Nick

Es gibt hier einige Informationen, zu viel zum Auflisten hier . Es kann davon abhängen, welchen Anbieter Sie verwenden und wie der refresh-token verwendet werden darf.

5
Shane O'Grady

Ähnlich wie bei anderen Antworten folgte ich diesem Ansatz, bei dem das Modell verwendet wird, das die Authentifizierungs- und Aktualisierungs-Token speichert, und API-Interaktionen von dieser Logik abstrahiert.

Siehe https://stackoverflow.com/a/51041855/1392282

0
Nuno Silva