我在rails中使用omniauth-oauth2来验证支持oauth2的站点。做完oauth之后,该网站给了我以下内容,然后我将其保存到数据库中:
是否有omniauth方法在令牌过期后自动刷新令牌,还是应该编写自定义代码来执行相同操作?
如果要编写自定义代码,帮助程序是编写逻辑的正确位置吗?
答案 0 :(得分:20)
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
(或开发)中设置的环境变量
答案 1 :(得分:18)
实际上,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
在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!
答案 2 :(得分:6)
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
答案 3 :(得分:5)
这里有一些信息,列出here太多了。这可能取决于您使用的提供商以及refresh-token
答案 4 :(得分:0)
与其他答案类似,我采用了这种方法,即使用存储身份验证和刷新令牌的模型,从该逻辑中提取API交互。
答案 5 :(得分:-2)
男孩,这本来很难解决的。
这是我们用来向d1.join(d7)
d2.join(d6)
d3.join(d5)
d4.join(d8)
提供授权的完整,有效的实现,该实现使用Devise,Omniauth和OAuth2 gem。 google-api-client
类封装了有关提取omniauth信息,根据需要刷新自身以及提供可用作GoogleAuthToken
gem的授权的访问令牌的知识。
google-api-client
然后是用法:
# Using the OAuth2 gem for auth in `google-api-client` is not quite enough, and requires a mixin
# for the `apply!` method.
# https://github.com/googleapis/google-api-ruby-client/issues/296#issuecomment-147545845
module GoogleAuthorizationOAuth2AccessTokenPatch
def apply!(headers)
headers['Authorization'] = "Bearer #{token}"
end
end
class GoogleAuthToken < ApplicationRecord
OMNIAUTH_CONFIG_NAME = :google_oauth2
OAuth2::AccessToken.include GoogleAuthorizationOAuth2AccessTokenPatch
def self.from_omniauth(omniauth)
provider, uid, info, credentials = omniauth.provider, omniauth.uid, omniauth.info, omniauth.credentials
GoogleAuthToken.new(
uid: uid,
provider: provider,
name: info.name,
email: info.email,
image: info.image,
token: credentials.token,
refresh_token: credentials.refresh_token,
expires_at: credentials.expires_at,
)
end
def access_token
return @access_token if @access_token.present? && !@access_token.expired?
@access_token = build_or_refresh_access_token
end
private def build_or_refresh_access_token
client_id = Devise.omniauth_configs[OMNIAUTH_CONFIG_NAME].strategy.client_id
client_secret = Devise.omniauth_configs[OMNIAUTH_CONFIG_NAME].strategy.client_secret
client = Devise.omniauth_configs[OMNIAUTH_CONFIG_NAME].strategy_class.new(nil, client_id, client_secret).client
access_token = OAuth2::AccessToken.new(client, token, refresh_token: refresh_token, expires_at: expires_at)
if access_token.expired?
access_token = access_token.refresh!
update!(token: access_token.token, refresh_token: access_token.refresh_token, expires_at: access_token.expires_at)
end
access_token
end
end
显然,您会希望# USAGE
require 'google/apis/calendar_v3'
# creating a GoogleAuthToken for the first time, e.g. from the `omniauth_callbacks_controller`
token = GoogleAuthToken.from_omniauth(request.env['omniauth.auth'])
token.save!
# inside of whatever client wrapper or whatever you want
client = Google::Apis::CalendarV3::CalendarService.new
client.authorization = token.access_token
client.list_calendar_lists # or whatever
属于有意义的事物,例如GoogleAuthToken
,您可以根据需要进行连接。