尝试覆盖Google Auth商店中的FileTokenStore.new

时间:2020-06-09 16:56:13

标签: ruby-on-rails ruby oauth-2.0

我正在使用Google日历的API,尝试存储令牌信息时遇到问题。通常,这是这样的:

#!/usr/bin/env ruby
require "google/apis/calendar_v3"
require "googleauth"
require "date"
require "fileutils"
require "googleauth/stores/file_token_store"

TOKEN_PATH = "token.yaml".freeze
CREDS = {"installed" => xyz}
def authorized
    client_id = Google::Auth::ClientId.from_hash CREDS
    token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
    authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
    user_id = "default"
    credentials = authorizer.get_credentials user_id
end

只要token.yaml文件存在于当前目录中,它就只会加载该文件。但是,我不想将此信息存储在文件中,而是将其加载到Ruby / Rails代码本身中。

我遇到了Use Google::Auth::Stores::FileTokenStore with database作为潜在的解决方法,但是我仍然遇到相同的问题。

以下是我的token_store.rb文件的示例:

# token_store.rb
require "googleauth/stores/file_token_store"
module Google
  module Auth
    module Stores
      class DatabaseTokenStore < Google::Auth::TokenStore
        def new
          {"client_id":"[redacted]","access_token":"[redacted]","refresh_token":"[redacted]","scope":["https://www.googleapis.com/auth/calendar.events"],"expiration_time_millis":1591721243000}.to_json
        end
      end
    end
  end
end

这是我的test.rb文件:

#!/usr/bin/env ruby
require "google/apis/calendar_v3"
require "googleauth"
require "date"
require "fileutils"
require "pry"
require './token_store.rb'
include Google::Auth::Stores

OOB_URI = "urn:ietf:wg:oauth:2.0:oob".freeze
APPLICATION_NAME = "[redacted]".freeze
# The file token.yaml stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
TOKEN_PATH = "token.yaml".freeze
SCOPE = Google::Apis::CalendarV3::AUTH_CALENDAR_EVENTS

CREDS = {"installed" =>{"client_id" => "[redacted]","project_id" =>"[redacted]","auth_uri" =>"https://accounts.google.com/o/oauth2/auth","token_uri" =>"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url" => "https://www.googleapis.com/oauth2/v1/certs","client_secret" =>"[redacted]","redirect_uris" => ["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}

##
# Ensure valid credentials, either by restoring from the saved credentials
# files or intitiating an OAuth2 authorization. If authorization is required,
# the user's default browser will be launched to approve the request.
#
# @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
def authorize
    client_id = Google::Auth::ClientId.from_hash CREDS
    token_store = Google::Auth::Stores::DatabaseTokenStore.new
    authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
    user_id = "default"
    credentials = authorizer.get_credentials user_id
    if credentials.nil?
        url = authorizer.get_authorization_url base_url: OOB_URI
        puts "Open the following URL in the browser and enter the " \
        "resulting code after authorization:\n" + url
        code = gets
        credentials = authorizer.get_and_store_credentials_from_code(
            user_id: user_id, code: code, base_url: OOB_URI
        )
    end
    credentials
end

# Initialize the API
calendar_id = "[redacted]"
service = Google::Apis::CalendarV3::CalendarService.new
service.client_options.application_name = APPLICATION_NAME
service.authorization = authorize

到达此行的时间:

credentials = authorizer.get_credentials user_id

出现以下错误:

[4] pry(main)> credentials = authorizer.get_credentials user_id
RuntimeError: Not implemented
from /Library/Ruby/Gems/2.6.0/gems/googleauth-0.12.0/lib/googleauth/token_store.rb:47:in `load'

如果我看一下token_store,它似乎已经正确定义了:

[5] pry(main)> token_store
=> #<Google::Auth::Stores::DatabaseTokenStore:0x00007fc565bd7400>

尽管从文件中加载它看起来却大不相同:

[7] pry(main)> token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
=> #<Google::Auth::Stores::FileTokenStore:0x00007fc567942b70
 @store=#<Psych::Store:0x00007fc567942b48 @abort=false, @filename="token.yaml", @lock=#<Thread::Mutex:0x00007fc567942a58>, @opt={}, @thread_safe=false, @ultra_safe=false>>

如何将token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH转换为从变量中加载数据而不必将其保存在本地?

解决方案尝试1

这是更新的test.rb

#!/usr/bin/env ruby
require "google/apis/calendar_v3"
require "googleauth"
require "date"
require "fileutils"
require "pry"
#require "googleauth/stores/file_token_store"
require './token_store.rb'
include Google::Auth::Stores

OOB_URI = "urn:ietf:wg:oauth:2.0:oob".freeze
APPLICATION_NAME = "[redacted]".freeze
# The file token.yaml stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
TOKEN_PATH = "token.yaml".freeze
SCOPE = Google::Apis::CalendarV3::AUTH_CALENDAR_EVENTS

CREDS = {"installed" =>{"client_id" => "[redacted]","project_id" =>"[redacted]","auth_uri" =>"https://accounts.google.com/o/oauth2/auth","token_uri" =>"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url" => "https://www.googleapis.com/oauth2/v1/certs","client_secret" =>"ScD4aFP-xw5ulWTeSJnYWQPi","redirect_uris" => ["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}

##
# Ensure valid credentials, either by restoring from the saved credentials
# files or intitiating an OAuth2 authorization. If authorization is required,
# the user's default browser will be launched to approve the request.
#
# @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
def authorize
    client_id = Google::Auth::ClientId.from_hash CREDS
    #token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
    store = {"client_id":"[redacted]","access_token":"[redacted]","refresh_token":"1//0d_k9oyIPv5CeCgYIARAAGA0SNwF-L9IrWtHY2lpGHJSuz8Brh9whd8tEPIenoZaK_dpJO4_wkCCaByT45gRFEmncjDhPQyRCcEQ","scope":["https://www.googleapis.com/auth/calendar.events"],"expiration_time_millis":1591721243000}
    token_store = Google::Auth::Stores::MemoryTokenStore.new(store: store)
    authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
    user_id = "default"
    credentials = authorizer.get_credentials user_id
    if credentials.nil?
        url = authorizer.get_authorization_url base_url: OOB_URI
        puts "Open the following URL in the browser and enter the " \
        "resulting code after authorization:\n" + url
        code = gets
        credentials = authorizer.get_and_store_credentials_from_code(
            user_id: user_id, code: code, base_url: OOB_URI
        )
    end
    credentials
end

calendar_id = "[redacted]"
service = Google::Apis::CalendarV3::CalendarService.new
service.client_options.application_name = APPLICATION_NAME
service.authorization = authorize

# Insert event into calendar
event = Google::Apis::CalendarV3::Event.new({
    :summary => 'event title',
    :location => 'event address',
    :description => 'event description',
    :start => {
        :date_time => '2020-06-28T09:00:00-07:00'
    },
    :end => {
        :date_time => '2020-06-28T17:00:00-07:00'
    }
 })
service.insert_event(calendar_id, event)

这是我更新的token_store.rb

require "googleauth/stores/file_token_store"
module Google
  module Auth
    module Stores
      class MemoryTokenStore < Google::Auth::TokenStore
        def initialize(options = {})
          @store = options[:store]
        end

        def load(id)
          store[id]
        end

        def store(id, token)
          store[id] = token
        end

        def delete(id)
          store.delete(id)
        end
      end
    end
  end
end

运行./test.rb时,发生以下错误:

Traceback (most recent call last):
        5: from ./test.rb:51:in `<main>'
        4: from ./test.rb:34:in `authorize'
        3: from /Library/Ruby/Gems/2.6.0/gems/googleauth-0.12.0/lib/googleauth/user_authorizer.rb:127:in `get_credentials'
        2: from /Library/Ruby/Gems/2.6.0/gems/googleauth-0.12.0/lib/googleauth/user_authorizer.rb:250:in `stored_token'
        1: from /Users/nutella/Downloads/test/google-calendar/token_store.rb:11:in `load'
/Users/myuser/Downloads/test/google-calendar/token_store.rb:14:in `store': wrong number of arguments (given 0, expected 2) (ArgumentError)

1 个答案:

答案 0 :(得分:1)

您至少需要实现load方法(+ storedelete)。否则,它将引发Not implemented错误(https://github.com/googleapis/google-auth-library-ruby/blob/master/lib/googleauth/token_store.rb#L47)。

require "googleauth/stores/file_token_store"

module Google
  module Auth
    module Stores
      class StaticTokenStore < Google::Auth::TokenStore
        def load(id)
          {
            "client_id": "[redacted]",
            "access_token":"[redacted]",
            "refresh_token":"[redacted]",
            "scope":  ["https://www.googleapis.com/auth/calendar.events"],
            "expiration_time_millis":1591721243000
          }.to_json
        end
      end
    end
  end
end

还请注意,在Ruby中,构造函数称为initialize,而不是new。此外,您没有将JSON数据分配给任何对象。所以这行不通:

def new
  {"client_id":"[redacted]","access_token":"[redacted]","refresh_token":"[redacted]","scope":["https://www.googleapis.com/auth/calendar.events"],"expiration_time_millis":1591721243000}.to_json
end

https://www.geeksforgeeks.org/ruby-constructors/


编辑

这是内存中的存储器

module Google
  module Auth
    module Stores
      class MemoryTokenStore < Google::Auth::TokenStore
        attr_reader :store
        def initialize(options = {})
          @store = options[:store]
        end

        def load(id)
          store[id]
        end

        def store(id, token)
          store[id] = token
        end

        def delete(id)
          store.delete(id)
        end
      end
    end
  end
end

store = {
  "client_id":                "[redacted]",
  "access_token":             "[redacted]",
  "refresh_token":            "[redacted]",
  "scope":                    ["https://www.googleapis.com/auth/calendar.events"],
  "expiration_time_millis":   1591721243000
}

Google::Auth::Stores::MemoryTokenStore.new(store: store)