ruby Azure下载blob:SAS令牌不起作用“签名不匹配”

uwopmtnx  于 2023-03-22  发布在  Ruby
关注(0)|答案(1)|浏览(114)

我使用Ruby生成一个blob URL。例如:
https://anasstoragetest2023.blob.core.windows.net/telestream/test.mov?sp=r&st=2023-03-14T20:23:04Z&se=2023-03-18T20:23:04Z&spr=https&sv=2021-12-02&sr=b&sig=6wpeYAlfpnGLPtk5PcIe/P+0q+XeLkIT6XLFR6uY5Os=
我得到的错误是“签名不匹配”:

<Error>
   <Code>AuthenticationFailed</Code>
   <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:0daa3721-e01e-0002-3049-58f5bf000000 Time:2023-03-16T20:55:10.7515529Z</Message>
   <AuthenticationErrorDetail>Signature did not match. String to sign used was r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov https 2021-12-02 b </AuthenticationErrorDetail>
  </Error>

尽管代码输出显示签名字符串与错误消息中记录的字符串相同:

String to sign: r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov   https 2021-12-02 b

我知道Azure here提供了一个SAS生成器,但它也会生成相同的错误:

blob_path = "/blob/#{account_name}/#{container_name}/#{blob_name}"
signature = 
    Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(account_name, account_key)
sas_token = 
    signature.generate_service_sas_token(blob_path, service: 'b', resource: 'b')

puts "\nCreated SAS token: #{sas_token}"
url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{sas_token}"
puts "\nCreated URL: #{url}"

下面是自定义ruby代码。我用ruby 3.1.3和2.6.8都试过了,都用了gem install azure-storage-blob
任何帮助将不胜感激!

def generate_blob_url(account_name, account_key, container_name, blob_name)
start_time = Time.now
days = 60*60*24*2

signed_permissions = "r"
signed_start = (start_time - days).utc.iso8601
signed_expiry = (start_time + days).utc.iso8601
canonicalized_resource = "/blob/#{account_name}/#{container_name}/#{blob_name}"
signed_identifier = ""
signed_ip = ""
signed_protocol = "https"
signed_version = "2021-12-02" # "2018-11-09"
signed_resource = "b"
signed_snapshottime = ""
rscc = ""
rscd = ""
rsce = ""
rscl = ""
rsct = ""

string_to_sign = signed_permissions + "\n" +
      signed_start + "\n" +
      signed_expiry + "\n" +
      canonicalized_resource + "\n" +
      signed_identifier + "\n" +
      signed_ip + "\n" +
      signed_protocol + "\n" +
      signed_version + "\n" +
      signed_resource + "\n" +
      signed_snapshottime + "\n" +
      rscc + "\n" +
      rscd + "\n" +
      rsce + "\n" +
      rscl + "\n" +
      rsct

puts "\nString to sign: #{string_to_sign.gsub("\n", " ")}"
sig = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', account_key, string_to_sign))
token = "sp=#{signed_permissions}&st=#{signed_start}&se=#{signed_expiry}&spr=#{signed_protocol}&sv=#{signed_version}&sr=#{signed_resource}&sig=#{sig}"
puts "\nGenerated token: #{token}"

url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{CGI.escape(token)}"
end
jogvjijk

jogvjijk1#

所以,
azure-ruby-storage客户端库不工作。signature generator已过时。
我设法修复了自定义代码。我缺少了一堆需要位于签名主体之间的换行符。Azure在生成签名之前不只是从签名主体中取出额外的换行符,这是荒谬的。甚至错误消息也不包括这些换行符。
不管怎样,下面是固定代码:

def run_sample
    
    account_name = "*****"
    account_key = "*****"
    container_name = "my_container"
    blob_name = "my_blob"
    
    
    now = Time.now
    start_time = Time.new(now.year, now.month, now.day, 0, 0, 0, "Z")
    expiry_duration = 60*60*24*2

    sas_token = generate_signature(
        account_name, account_key, container_name, blob_name, start_time, expiry_duration)
    puts "\nSAS token: #{sas_token}"
    url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{sas_token}"
    puts "\nURL: #{url}"
end

def generate_signature(account_name, account_key, container_name, blob_name, start_time, expiry_duration)  
    signed_permissions = "r"
    signed_start = (start_time).iso8601
    signed_expiry = (start_time + expiry_duration).iso8601
    canonicalized_resource = "/blob/#{account_name}/#{container_name}/#{blob_name}"
    signed_protocol = "https"
    signed_version = "2021-12-02"
    signed_resource = "b"
    
    wc = "\n"
    string_to_sign = 
        signed_permissions + wc +
        signed_start + wc +
        signed_expiry + wc +
        canonicalized_resource + wc +
        wc + # identifier
        wc + # ip
        signed_protocol + wc +
        signed_version + wc +
        signed_resource + wc +
        wc + # timestamp 
        wc + # cache control
        wc + # content disposition
        wc + # content encoding
        wc + # content language
        wc # content type 
          
    puts "\nString to sign:\n#{string_to_sign.gsub(wc, " ")}"
    
    sig = CGI.escape(
            Base64.strict_encode64(
                OpenSSL::HMAC.digest('sha256', 
                    Base64.decode64(account_key), string_to_sign)))
    
    puts "\nSignature: #{sig}"

    token = "sp=#{signed_permissions}&st=#{signed_start}&se=#{signed_expiry}&spr=#{signed_protocol}&sv=#{signed_version}&sr=#{signed_resource}&sig=#{sig}"
end

run_sample

相关问题