Assinando URLs do Amazon S3

Usando o aws gem ( https://github.com/appoxy/aws/ ), você pode manipular facilmente as ações de colocar e obter em um intervalo, mas se você definiu seus direitos de intervalo como privados , precisará de um pouco mais de código para fornecer e urls com limite de tempo.

O AWS S3 tem alguma documentação sobre o tópico: http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html e é muito fácil de seguir e fazer funcionar. Ainda assim, o exemplo não é código Ruby, então aqui está um pronto para usar.

Um url S3 assinado é composto do clássico get url, em que você adiciona seu ID de chave do AWS Access, uma data de expiração (no formato Unix) e uma assinatura. Os dois primeiros são fáceis, a assinatura é onde está a diversão.

A assinatura é basicamente uma string codificada em base64 feita a partir de um resumo OpenSSL HMAC.

Você precisa de duas coisas como parâmetros iniciais:

  • data de expiração : uma hora Unix no futuro
  • caminho : o caminho do arquivo no intervalo S3 (isso mesmo, não inclui o nome do intervalo)

Você precisa criar um novo resumo SHA1 usando a lib OpenSSL:

digest = OpenSSL::Digest::Digest.new('sha1')

Em seguida, você cria uma string correspondente à solicitação http que deseja fazer:

can_string = "GETnnn#{expire_date}n/#{S3_BUCKET}/#{path}"

Você pode fazer o resumo final usando essa string, a solicitação anterior e a chave S3:

hmac = OpenSSL::HMAC.digest(digest, S3_SECRET_ACCESS_KEY, can_string)

A assinatura é feita a partir desse resumo usando o codificador Base64:

signature = URI.escape(Base64.encode64(hmac).strip).encode_signs

Em seguida, você só precisa adicionar tudo isso para obter o url assinado:

"https://s3.amazonaws.com/#{S3_BUCKET}/#{path}?AWSAccessKeyId=#{S3_ACCESS_KEY_ID}&Expires=#{expire_date}&Signature=#{signature}"

Todo o código: https://gist.github.com/3434417 .

Os Base64.encode64 e URI.escape métodos nem sempre codificar alguns personagens como “+”, “?” etc … Você precisa fazer isso sozinho. Se você verificar a essência do link acima, encontrará String :: encode_signs que codifica esses caracteres corretamente.