Google Cloud Storage URL签名

时间:2019-04-16 08:01:55

标签: python elixir google-cloud-storage

我有一个签名者,非常适合从GCS上载和下载。大!签名者看起来像这样:

def sign_url(client, bucket, key, opts \\ []) do
  verb = opts[:verb] || "GET"
  md5_digest = opts[:md5_digest] || ""
  content_type = opts[:content_type] || ""
  expires = opts[:expires] || Utils.years(10)
  resource = "/#{bucket}/#{key}"

  signature =
    [verb, md5_digest, content_type, expires, resource]
    |> Enum.join("\n")
    |> generate_signature(client)

  url = "#{@base_url}#{resource}"

  qs =
    %{
      "GoogleAccessId" => client.client_email,
      "Expires" => expires,
      "Signature" => signature
    }
    |> URI.encode_query()

  Enum.join([url, "?", qs])
end

defp generate_signature(string, client) do
  private_key = get_private_key(client)

  string
  |> :public_key.sign(:sha256, private_key)
  |> Base.encode64()
end

defp get_private_key(client) do
  client.private_key
  |> :public_key.pem_decode()
  |> Kernel.hd()
  |> :public_key.pem_entry_decode()
end

我遇到的问题是是否要添加一个x-goog标头,例如x-goog-copy-source。这样做,我得到了错误:

The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

现在,我知道签名URL支持自定义标头,但是我不确定如何更新签名以支持它。我找不到包括该文档在内的在线资源,包括Google文档。

其他人对此有经验吗?

谢谢

1 个答案:

答案 0 :(得分:2)

我稍微修改了您的代码以添加标题。期望它们在字符串中过期后才能签名。

我对Elixir的了解还不够,但是希望这可以为您指明正确的方向。它基于Ruby存储实现(https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-storage/lib/google/cloud/storage/file/signer_v2.rb#L62

编辑:可以在here中找到有关此构造的文档。

def sign_url(client, bucket, key, opts \\ []) do
  verb = opts[:verb] || "GET"
  md5_digest = opts[:md5_digest] || ""
  content_type = opts[:content_type] || ""
  expires = opts[:expires] || Utils.years(10)
  resource = "/#{bucket}/#{key}"
  headers = 
    Enum.map(opts[:headers], fn ({key, value}) -> "#{key}:#{value}" end)
           |> Enum.join("\n")

  signature =
    [verb, md5_digest, content_type, expires, headers, resource]
    |> Enum.join("\n")
    |> generate_signature(client)

  url = "#{@base_url}#{resource}"

  qs =
    %{
      "GoogleAccessId" => client.client_email,
      "Expires" => expires,
      "Signature" => signature
    }
    |> URI.encode_query()

  Enum.join([url, "?", qs])
end

defp generate_signature(string, client) do
  private_key = get_private_key(client)

  string
  |> :public_key.sign(:sha256, private_key)
  |> Base.encode64()
end

defp get_private_key(client) do
  client.private_key
  |> :public_key.pem_decode()
  |> Kernel.hd()
  |> :public_key.pem_entry_decode()
end