为azure服务总线/ eventhubs生成有效的Authorization标头

时间:2016-04-18 10:53:24

标签: ruby azure azure-eventhub

我正在尝试在ruby脚本中使用SAS身份验证,并且我不断从事件中心获得401(拒绝访问)响应,似乎我正在错误地生成SAS令牌。

下面是我使用的代码,它基于https://azure.microsoft.com/en-us/documentation/articles/service-bus-sas-overview/我已经重写为ruby的Javascript示例(请注意它可能不是惯用的)

require "optparse"
require "CGI"
require 'openssl'
require "base64"
require "Faraday"
require 'Digest'

def generateToken(url,keyname,keyvalue)
    encoded = CGI::escape(url)
    ttl = (Time.now + 60*5).to_i
    signature = "#{encoded}\n#{ttl}".encode('utf-8')
    # puts signature
    key = Base64.strict_decode64(keyvalue)
    dig  = OpenSSL::HMAC.digest('sha256', key, signature)
    # dig = Digest::HMAC.digest(signature, key, Digest::SHA256)
    hash = CGI.escape(Base64.strict_encode64(dig))
    # puts hash
    return "SharedAccessSignature sig=#{hash}&se=#{ttl}&skn=#{keyname}&sr=#{encoded}" 
end

def build_connection(url,token)
    conn = Faraday.new(:url => url) do |faraday|
        faraday.request  :url_encoded             # form-encode POST params
        faraday.response :logger                  # log requests to STDOUT
        faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
    end
    conn.headers['Content-Type'] = 'application/json'
    conn.headers['Authorization'] = token
    return conn
end


if __FILE__ == $0
    ARGV << '-h' if ARGV.empty?
    options = {}
    OptionParser.new do |opts|
        opts.banner = "Usage: generateSasToken.rb [options]"
        opts.on('-u URL', '--url URL', 'url for access') { |v| options[:url] = v }
        opts.on('--keyname NAME','set key name') { |v| options[:keyname] = v }
        opts.on('--key KEY','set key value') { |v| options[:keyvalue] = v }
        opts.on_tail("-h", "--help", "Show this message") do
            puts opts
            exit
        end
    end.parse!
    token = generateToken(options[:url],options[:keyname],options[:keyvalue])
    puts token
    conn = build_connection(options[:url],token)
    puts conn.headers
    response =  conn.post do |req|
                    req.body = '{"temprature":50}'
                    req.headers['content-length'] = req.body.length.to_s
                end
    puts response
end

任何帮助理解令牌不正确的原因都会很棒

1 个答案:

答案 0 :(得分:0)

将我的代码与python sdk进行比较后,这是生成令牌的正确方法:

require "optparse"
require "CGI"
require 'openssl'
require "base64"
require "Faraday"
require 'Digest'

def generateToken(url,keyname,keyvalue)
    encoded = CGI::escape(url)
    ttl = (Time.now + 60*5).to_i
    signature = "#{encoded}\n#{ttl}"
    # puts signature
    key = keyvalue
    #dig  = OpenSSL::HMAC.digest('sha256', key, signature)
    dig = Digest::HMAC.digest(signature, key, Digest::SHA256)
    hash = CGI.escape(Base64.strict_encode64(dig))
    # puts hash
    return "SharedAccessSignature sig=#{hash}&se=#{ttl}&skn=#{keyname}&sr=#{encoded}" 
end

def build_connection(url,token)
    conn = Faraday.new(:url => url) do |faraday|
        faraday.request  :url_encoded             # form-encode POST params
        faraday.response :logger                  # log requests to STDOUT
        faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
    end
    conn.headers['Content-Type'] = 'application/json'
    conn.headers['Authorization'] = token
    return conn
end


if __FILE__ == $0
    ARGV << '-h' if ARGV.empty?
    options = {}
    OptionParser.new do |opts|
        opts.banner = "Usage: generateSasToken.rb [options]"
        opts.on('-u URL', '--url URL', 'url for access') { |v| options[:url] = v }
        opts.on('--keyname NAME','set key name') { |v| options[:keyname] = v }
        opts.on('--key KEY','set key value') { |v| options[:keyvalue] = v }
        opts.on_tail("-h", "--help", "Show this message") do
            puts opts
            exit
        end
    end.parse!
    token = generateToken(options[:url],options[:keyname],options[:keyvalue])
    conn = build_connection(options[:url],token)
    puts conn.headers
    response =  conn.post do |req|
                    req.body = '{"temprature":50}'
                    req.headers['content-length'] = req.body.length.to_s
                end
    puts response
end

这比预期的要简单得多,无需编码为utf8或解密密钥。