32 Stimmen

Aktualisieren Sie das Token unter Verwendung von Omniauth-oauth2 in der Rails-Anwendung

Ich benutze omniauth-oauth2 in Rails, um mich bei einer Website zu authentifizieren, die oauth2 unterstützt. Nachdem ich den OAuth-Tanz durchgeführt habe, gibt mir die Website Folgendes, das ich dann in die Datenbank speichere:

  1. Zugriffstoken
  2. Ablaufdatum (Ticks)
  3. Refresh-Token

Gibt es eine omniauth-Methode, um das Token automatisch zu erneuern, nachdem es abgelaufen ist, oder sollte ich benutzerdefinierten Code schreiben, um dies zu tun?

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

26voto

ganeshran Punkte 3434

Omniauth bietet diese Funktionalität nicht von Haus aus an, daher habe ich die vorherige Antwort und eine weitere SO-Antwort verwendet, um den Code in meinem Modell User.rb zu schreiben.

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 'Gespeichert'
  end
end

def token_expired?
  expiry = Time.at(self.expiresat) 
  return true if expiry < Time.now # abgelaufener Token, daher sollten wir schnell zurückgeben
  token_expires_at = expiry
  save if changed?
  false # Token nicht abgelaufen. :D
end

Und bevor Sie den API-Aufruf mit dem Zugriffstoken machen, können Sie die Methode so aufrufen, wobei current_user der angemeldete Benutzer ist.

current_user.refresh_token_if_expired

Stellen Sie sicher, dass Sie das rest-client Gem installieren und die require-Anweisung require 'rest-client' in der Modelldatei hinzufügen. Die ENV['DOMAIN'], ENV['APP_ID'] und ENV['APP_SECRET'] sind Umgebungsvariablen, die in config/environments/production.rb (oder development) festgelegt werden können.

24voto

Eero Punkte 4544

Tatsächlich haben das omniauth-oauth2 Gem und dessen Abhängigkeit, oauth2, beide eine gewisse Aktualisierungslogik eingebaut.

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

# Aktualisiert den aktuellen Zugriffstoken
#
# @return [AccessToken] ein neuer Zugriffstoken
# @note Optionen sollten auf den neuen Zugriffstoken übertragen werden
def refresh!(params = {})
  fail('Ein Aktualisierungs-Token ist nicht verfügbar') 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

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?

Daher können Sie es möglicherweise nicht direkt mit omniauth-oauth2 tun, aber Sie können sicherlich etwas Ähnliches mit oauth2 tun:

client = strategy.client # von Ihrer omniauth oauth2 Strategie
token = OAuth2::AccessToken.from_hash client, record.to_hash
# oder
token = OAuth2::AccessToken.new client, token, {expires_at: 123456789, refresh_token: "123"}
token.refresh!

7voto

Nick Punkte 2566

Eeros Antwort hat mir den Weg freigeschaltet, um dieses Problem zu lösen. Ich habe eine Hilfsfunktion für meine Klassen, die mir einen GmailService liefert. Im Rahmen dieses Vorgangs wird das Benutzerobjekt (das die Google-Authentifizierungsinformationen enthält) überprüft, ob es abgelaufen ist. Falls ja, wird es aktualisiert, bevor der Service zurückgegeben wird.

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

  # Ist das Benutzer-Token abgelaufen?
  if user.google_token_expire.to_datetime.past?
    oauth = OmniAuth::Strategies::GoogleOauth2.new(
      nil, # App - nil scheint in Ordnung zu sein?!
      "XXXXXXXXXX.apps.googleusercontent.com", # Client-ID
      "ABC123456" # Client-Geheimnis
    )
    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("VERDAMMT - HAT NICHT FUNKTIONIERT!")
    end
  end

  mail.authorization = user.google_access_token

  mail
end

5voto

Shane O'Grady Punkte 2465

Es gibt auch hier einige Informationen, zu viel, um sie alle aufzulisten hier. Es könnte von dem Anbieter abhängen, den Sie verwenden, und deren erlaubter Verwendung des refresh-token.

0voto

Nuno Silva Punkte 708

Ähnlich wie bei anderen Antworten bin ich diesem Ansatz gefolgt, bei dem das Modell, das die Authentifizierungs- und Auffrischungstoken speichert, verwendet wird, um die API-Interaktionen von dieser Logik abzubstrahieren.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X