J'utilise omniauth-oauth2 dans Rails pour m'authentifier sur un site prenant en charge oauth2. Après avoir fait la danse oauth, le site me donne ce qui suit, que je persiste dans la base de données:
Existe-t-il une méthode omniauth pour actualiser automatiquement le jeton après son expiration ou devrais-je écrire un code personnalisé pour faire de même?
Si un code personnalisé doit être écrit, un assistant est-il le bon endroit pour écrire la logique?
Omniauth n'offrant pas cette fonctionnalité immédiatement, j'ai utilisé la réponse précédente et une autre réponse SO pour écrire le code dans mon modèle 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
Et avant de passer l'appel d'API à l'aide du jeton d'accès, vous pouvez appeler la méthode de cette manière, où utilisateur_diffusé est l'utilisateur connecté.
current_user.refresh_token_if_expired
Veillez à installer le fichier rest-client gem et à ajouter la directive require require 'rest-client'
dans le fichier de modèle. ENV['DOMAIN']
, ENV['APP_ID']
et ENV['APP_SECRET']
sont des variables d'environnement pouvant être définies dans config/environments/production.rb
(ou développement)
En fait, la gem omniauth-oauth2 et sa dépendance, oauth2 , intègrent toutes les deux une logique de rafraîchissement.
Voir dans 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
Et dans https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L74 :
self.access_token = access_token.refresh! if access_token.expired?
Donc, vous ne pourrez peut-être pas le faire directement avec omniauth-oauth2, mais vous pouvez certainement faire quelque chose dans le sens de ceci avec oauth2:
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!
La réponse d'Eero m'a ouvert un chemin pour résoudre ce problème. J'ai un problème d'assistance pour mes cours qui me permet d'obtenir un service Gmail. Dans le cadre de ce processus, l'objet utilisateur (qui contient les informations d'authentification de Google) est vérifié s'il a expiré. Si tel est le cas, il est actualisé avant de renvoyer le service.
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
Il y a quelques informations ici, trop à énumérer ici . Cela peut dépendre du fournisseur que vous utilisez et de l’utilisation autorisée du refresh-token
De la même manière que d’autres réponses, j’ai suivi cette approche, où le modèle stockant l’authentification et les jetons d’actualisation est utilisé, faisant abstraction des interactions entre API et cette logique.