ruby-on-rails - google - rails doorkeeper api
Actualizar token con Omniauth-oauth2 en la aplicaciĆ³n Rails (5)
Aquí hay información, demasiado para enumerar here . Puede depender del proveedor que está utilizando y su uso permitido del refresh-token
Estoy usando omniauth-oauth2 en rieles para autenticar en un sitio que admite oauth2. Después de hacer el baile de oauth, el sitio me da lo siguiente, que luego persisto en la base de datos:
- Token de acceso
- Expires_AT (ticks)
- Actualizar token
¿Existe un método omniauth para actualizar el token automáticamente después de que caduque o debo escribir un código personalizado para hacer lo mismo?
Si se va a escribir un código personalizado, ¿es un ayudante el lugar correcto para escribir la lógica?
De forma similar a otras respuestas, seguí este enfoque, donde se usa el modelo que almacena los tokens de autenticación y actualización, abstrayendo las interacciones de API de esa lógica.
Ver https://.com/a/51041855/1392282
De hecho, la gema omniauth-oauth2 y su dependencia, oauth2 , tienen incorporada alguna lógica de actualización.
Ver en 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
Y en https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L74 :
self.access_token = access_token.refresh! if access_token.expired?
Por lo tanto, es posible que no pueda hacerlo directamente con omniauth-oauth2, pero ciertamente puede hacer algo similar a esto con 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 respuesta de Eero me abrió un camino para resolver esto. Tengo una preocupación de ayuda para mis clases que me da un servicio de Gmail. Como parte de este proceso, el objeto de usuario (que contiene la información de autenticación de google) se verifica si ha caducado. Si es así, se actualiza antes de devolver el servicio.
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
Omniauth no ofrece esta funcionalidad lista para usar, por lo que utilicé la respuesta anterior y otra respuesta SO para escribir el código en mi modelo 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
Y antes de realizar la llamada API usando el token de acceso, puede llamar al método de esta manera, donde current_user es el usuario registrado.
current_user.refresh_token_if_expired
Asegúrese de instalar la gema rest-client y agregue la directiva require ''rest-client''
que require ''rest-client''
en el archivo de modelo. ENV[''DOMAIN'']
, ENV[''APP_ID'']
y ENV[''APP_SECRET'']
son variables de entorno que pueden configurarse en config/environments/production.rb
(o desarrollo)