2014-02-11 80 views
24

我在rails中使用omniauth-oauth2對支持oauth2的站點進行身份驗證。做OAuth技巧後,該網站給了我;下面,我再堅持到數據庫:在Rails應用程序中使用Omniauth-oauth2刷新令牌

  1. 訪問令牌
  2. Expires_AT(蜱)
  3. 刷新令牌

是否有omn​​iauth方法在過期後自動刷新令牌,還是應該編寫自定義代碼來執行相同的操作?

如果要編寫自定義代碼,是否是幫助程序編寫邏輯的正確位置?

回答

18

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寶石,並在模型文件中添加需要的指令require 'rest-client'。該ENV['DOMAIN']ENV['APP_ID']ENV['APP_SECRET']是可以在config/environments/production.rb(或開發)

+2

ENV ['DOMAIN']應該如何看起來像? – TiSer

+0

你應該正常化到UTC嗎?或者沒有關係... – ckarbass

+0

域名應該是:「https://accounts.google.com/o/oauth2/token」 –

5

這裏有一些信息,太多列出here。它可能取決於您使用的提供商以及它們允許的使用情況以及它們允許的使用情況refresh-token

15

事實上,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! 
+0

有沒有簡單的方法從Rails應用中的現有策略加載客戶端?就像Oauth2策略那樣,我最終宣佈了一個新客戶端:https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2。rb#L34 – bgentry

+0

我想你的問題是,我如何找到對現有OmniAuth策略的參考?一旦你有策略對象,它就有一個「客戶端」方法。這裏有其他人詢問有關尋找策略:http://stackoverflow.com/questions/13112430/find-loaded-providers-for-omniauth – Eero

+0

謝謝@Eero - 這導致我到我的修復下面:http://stackoverflow.com/a/38276378/224707 – Nick

4

艾羅的回答解鎖的路徑爲我解決這個問題。我有一個關於我的課程的幫助問題,它使我獲得了一個Gmail服務。作爲這個過程的一部分,用戶對象(包含谷歌身份驗證信息)會被檢查是否已過期。如果有,它會在返回服務之前刷新。

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 
+0

OmniAuth :: Strategies :: YOUR_PROVIDER(nil,client_id,secret)...這是訪問策略,然後訪問其客戶端的唯一方法嗎? – kukrt

相關問題