在Rails应用程序中使用Omniauth-oauth2刷新令牌

我在rails中使用omniauth-oauth2来validation支持oauth2的站点。 在做了oauth之后,该网站给了我以下内容,然后我将其保存到数据库中:

  1. 访问令牌
  2. Expires_AT(滴答)
  3. 刷新令牌

是否存在omniauth方法在令牌过期后自动刷新令牌,或者我应该编写自定义代码来执行相同的操作?

如果要编写自定义代码,帮助程序是编写逻辑的正确位置吗?

Omniauth不提供开箱即用的function所以我使用前面的答案和另一个SO答案在我的模型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 

在使用访问令牌进行API调用之前,您可以调用这样的方法,其中current_user是登录用户。

 current_user.refresh_token_if_expired 

确保安装rest-client gem并在模型文件中添加require指令require 'rest-client'ENV['DOMAIN']ENV['APP_ID']ENV['APP_SECRET']是环境变量,可以在config/environments/production.rb (或开发)中设置

实际上, omn​​iauth-oauth2 gem及其依赖项oauth2都内置了一些刷新逻辑。

请参阅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 

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

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

所以你可能无法直接使用omniauth-oauth2,但你可以用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! 

Eero的答案为我解开了这条道路。 我有一个帮助我的课程,让我得到一个GmailService。 作为此过程的一部分,如果用户对象(包含google身份validation信息)已过期,则会对其进行检查。 如果有,则在返回服务之前刷新。

 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 

这里有一些信息,这里列出的内容太多了。 它可能取决于您使用的提供程序,以及它们允许使用的refresh-token

与其他答案类似,我遵循这种方法,其中使用存储auth和刷新令牌的模型,从该逻辑中抽象API交互。

请参阅https://stackoverflow.com/a/51041855/1392282