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:
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?
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.
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!
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
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.
Ä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.