如何将带有秘钥的JSON文件上传到Heroku

19

我正在构建一个Rails应用程序,使用Google Api Client Library for Ruby从Google Analytics中获取数据。

我正在使用OAuth2,在本地机器的开发环境中可以使所有东西正常工作。问题是该库使用一个下载的文件 client_secrets.json 来存储两个密钥。

问题: 我正在使用Heroku,并需要一种方法将文件发送到其生产服务器。

我不想将此文件添加到我的github存储库中,因为该项目是公共的。

如果有一种方式可以临时将该文件添加到git中,推送到Heroku并从git中删除,则可以。我的感觉是密钥将在提交中,很难防止在github上显示。

已尝试: 据我所知,您无法通过Bash控制台将文件SCP到Heroku。我认为在这样做时,您会获得一个新的Dyno,您添加的任何内容都将是暂时的。我尝试过这个,但无法使SCP正常工作,因此不确定100%。

已尝试: 我尝试了将JSON文件存储在环境或配置变量中,但无法使其正常工作。如果有人有想法,这似乎是最好的途径。当Ruby将JSON转换为字符串或哈希时,我经常遇到麻烦,因此可能只需要在这里获得指导。

已尝试: 此外,我尝试找出一种方法,仅从JSON文件中提取密钥,将其放入Config Vars,并将JSON文件添加到git中。但是,我无法弄清如何将 ENV["KEY"] 放入JSON文件中。


示例代码 Google库有一个方法,该方法加载JSON文件以创建授权客户端。然后,客户端会获取令牌(或给出授权URL)。

client_secrets = Google::APIClient::ClientSecrets.load('client_secrets.json')
auth_client = client_secrets.to_authorization

请注意,在Google页面上的示例没有显示文件名,因为它使用了默认的ENV变量,该变量已设置为路径。

我认为如果ClientSecrets.load()方法只接受JSON、字符串或哈希并将其放入配置变量中,那么这一切都会更容易。

不幸的是,它似乎总是需要一个文件路径。当我提供JSON、字符串或哈希时,它就会崩溃。我在这里看到有人用p12密钥解决了这个问题,但我不确定如何在我的情况下复制这个方法。

未尝试:除了转移到AWS之外,我唯一的想法是将JSON文件放在AWS上,并在需要时让Rails获取它。我不确定是否可以即时完成这个操作,或者是否需要在Rails服务器启动时下载文件。看起来太麻烦了,但目前我已经花了几个小时在这个问题上,所以准备尝试。

这是我正在处理的特定控制器: https://github.com/dladowitz/slapafy/blob/master/app/controllers/welcome_controller.rb

5个回答

12

通过搜索 Github 我发现有人使用了一种不同的方法,它使用 JSON 字符串作为参数而不是文件路径:Google::APIClient::ClientSecrets.new(JSON.parse(ENV['GOOGLE_CLIENT_SECRETS']))

这让我可以将 JSON 封装到环境变量中。世界又恢复了理智。


你是如何在环境变量中存储JSON数据的(例如,换行符、引号)?我可以在控制台中使用这行代码导入它,但我尝试按照您在控制器中设置的方式进行设置,当调用此行时,在ClientSecrets的initialize函数中出现“Symbol无法隐式转换为整数”的错误。我没有问题尝试访问它失败的项目,所以它一定是在两者之间丢失了。 - paullj1
1
我正在使用 figaro gem,并将我的环境变量存储在 application.yml 中。在这个文件中,我设置了变量如下:GOOGLE_CLIENT_SECRETS: '{"web":{"client_id":"XXXXXX-XXXXXXXXXXXX.apps.googleusercontent.com","project_id":"XXXX-XXXX","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"XXXXXXXXXX","redirect_uris":["http://localhost:3000/oauthredirect"]}}' - David Ladowitz
1
在Heroku中,Config Var值几乎相同,但我删除了最外层的单引号。需要注意的一件事是,在我的解决方案中,我找到了一种不需要文件名的不同方法。最初我使用的是Google::APIClient::ClientSecrets.load()现在我使用的是Google::APIClient::ClientSecrets.new() - David Ladowitz

3

正如在此讨论串中所述,您可以设置三个环境变量来代替提供JSON密钥文件的路径:

GOOGLE_ACCOUNT_TYPE=service_account
GOOGLE_PRIVATE_KEY=XXX
GOOGLE_CLIENT_EMAIL=XXX

Source here.


这似乎使用Cloud自然语言API可以工作,并且节省了我很多麻烦。 - Nick
嗨@Nick - 抱歉又翻起旧账了 - 我也遇到同样的困境,想知道你是如何解决自然语言API的问题的? - gezquinndesign
@gezquinndesign 这是一个非生产应用程序,但最终我只是在development.rb中设置了ENV['GOOGLE_PRIVATE_KEY']等内容,然后它就可以工作了... - Nick

2
我在使用Google API时遇到了同样的问题。最终我使用openssl给p12文件分配了一个新的非常秘密的密码,将该新文件存储在repo中,然后将密码放入应用程序密钥和Heroku环境变量中。
这样,文件虽然在repo中,但没有密码就无法访问/读取。
这篇文章对于将默认的Google p12密码从“notasecret”更改为安全密码很有帮助:This
def authorize!
  @client.authorization = Signet::OAuth2::Client.new(
    #...
    :signing_key => key
  )
end

def key
  Google::APIClient::KeyUtils.load_from_pkcs12(key_path, ENV.fetch('P12_PASSPHRASE'))
end

def key_path
  "#{Rails.root}/config/google_key.p12"
end

0

使用Rails 7,我像这样加密了JSON凭据

首先运行bin/rails credentials:edit -e development

然后添加我的凭据:

  omniauth:
    google_oauth2:
      client_secrets: {"web":{"client_id":"my-client-id","project_id":"my-project-id","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":"my-client-secret","redirect_uris":["http://localhost:3000/users/auth/google_oauth2/callback","http://localhost:3000/contacts/gmail/callback"]}}

我这样使用它和ClientSecrets:

    def client_secrets
      @client_secrets ||= Google::APIClient::ClientSecrets.new(client_secrets_json)
    end

    def client_secrets_json
      Rails.application.credentials.dig(:omniauth, :google_oauth2, :client_secrets)
    end

0
对于将来遇到类似问题的人,这是我解决的方法:
    # GOOGLE_PLAY_CLIENT_SECRETS_JSON = "{\"web\":{\"client_id\":\"XXXXX", ...}}"
    json = ENV['GOOGLE_PLAY_CLIENT_SECRETS_JSON']

    file = File.open('client_secrets.json', 'w') do |f|
      f.write(json)
    end

    CLIENT_SECRETS = Google::APIClient::ClientSecrets.load('client_secrets.json')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接