oauth-2.0 在Rails应用程序中使用Omniauth-oauth2刷新标记

gijlo24d  于 2022-10-31  发布在  其他
关注(0)|答案(6)|浏览(160)

我在rails中使用omniauth-oauth2对支持oauth2的站点进行身份验证。完成oauthdance后,站点将向我提供以下内容,然后我将其保存到数据库中:
1.访问令牌
1.到期时间_AT(刻度)
1.刷新令牌
是否有omniauth方法在令牌过期后自动刷新令牌,或者我是否应该编写自定义代码来执行相同的操作?
如果要编写自定义代码,帮助器是否是编写逻辑的正确位置?

ctehm74n

ctehm74n1#

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

在使用访问令牌进行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(或开发)中设置的环境变量。

vwhgwdsa

vwhgwdsa2#

事实上,omniauth-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

而在www.example.com中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!
vnjpjtjt

vnjpjtjt3#

Eero的回答为我打开了一条解决这个问题的途径。我有一个关于我的类的助手,它为我提供了一个GmailService。作为这个过程的一部分,用户对象(包含google auth信息)会被检查是否过期。如果过期,它会在返回服务之前刷新。

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
nwo49xxi

nwo49xxi4#

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

ndh0cuux

ndh0cuux5#

与其他答案类似,我采用了这种方法,其中使用了存储auth和刷新令牌的模型,从该逻辑中抽象出API交互。
请参阅https://stackoverflow.com/a/51041855/1392282

yc0p9oo0

yc0p9oo06#

如果你使用devise,你可以创建一个新的策略,我猜如下,这样你就不需要到处重复客户端id和secret:


# first argument is something called app, but not sure what but nil seems to be fine.

Strategies::MyStrategy.new(nil, *Devise.omniauth_configs[:mystrategy].args)

相关问题