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

gan*_*ran 28 ruby-on-rails oauth oauth-2.0 omniauth ruby-on-rails-4

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

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

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

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

gan*_*ran 20

Omniauth不提供开箱即用的功能,所以我使用前面的答案和另一个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
Run Code Online (Sandbox Code Playgroud)

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

current_user.refresh_token_if_expired
Run Code Online (Sandbox Code Playgroud)

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

  • ENV ['DOMAIN']应该如何? (2认同)

Eer*_*ero 19

实际上,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
Run Code Online (Sandbox Code Playgroud)

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

self.access_token = access_token.refresh! if access_token.expired?
Run Code Online (Sandbox Code Playgroud)

所以你可能无法直接使用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!
Run Code Online (Sandbox Code Playgroud)

  • 是否有一种简单的方法可以从 Rails 应用程序中的现有策略加载客户端?我最终像 Oauth2 策略一样声明了一个新客户端:https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L34 (2认同)

Nic*_*ick 7

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

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
Run Code Online (Sandbox Code Playgroud)


Sha*_*ady 5

这里有一些信息,太多列出在这里.它可能取决于您使用的提供商,以及他们允许使用的提供商refresh-token