ruby 在函数中生成HMAC-SHA 256密钥不起作用,但在IRB中生成可以

b4qexyjb  于 2023-04-20  发布在  Ruby
关注(0)|答案(1)|浏览(90)

博士
生成**$sb_token全局变量(这是一个HMAC-SHA 256密钥)的函数似乎不能正确/准确地生成它,而如果我手动运行函数中的步骤,它会正确/准确地生成它。
我在IRB中调试Ruby脚本,遇到了一个奇怪的问题。
也许你会告诉我,我用错了变量,我很高兴能接受教育,但我不明白这里发生了什么。
我有一个函数,它生成了
$sb_token**变量(我并不完全理解OpenSSL / Base64 / hmac的所有用法,但我已经证明了这一点):

def get_service_bus_token()
    
    resourceUri = $resourceUri
    sasKeyName = $sasKeyName
    sasKey = $sasKey
    
    # url encoded
    encoded = ERB::Util.url_encode(resourceUri)
    
    # ttl
    timeNow = Time.now; $sb_token_timestamp = timeNow
    now = timeNow.to_i 
    minute = 60
    ttl = ((now ) + minute).to_s;
    #ttl = 1646428676.to_s
    
    # sig
    signature = encoded + '
    ' + ttl
        digest = OpenSSL::Digest.new('sha256')
        hmac = OpenSSL::HMAC.digest(digest, sasKey, signature)
        #hmac = OpenSSL::HMAC.hexdigest(digest, sasKey, signature)
        
        hash = Base64.strict_encode64(hmac)

    $sb_token = "SharedAccessSignature sr=" + encoded + "&sig=" + ERB::Util.url_encode(hash) + "&se=" + ttl + "&skn=" + sasKeyName;
    return $sb_token

end

当我执行上面的 get_service_bus_token() 函数时,$sb_token对象被创建并存储为全局变量。
我在另一个函数中使用**$sb_token对象作为Authorization头:
headers['Authorization'] = $sb_token
然后用这个头发出请求:
response = HTTParty.post(url, :headers=>headers, :body=>body )
这不起作用-我收到无效授权令牌响应:
#<Net::HTTPUnauthorized 401 SubCode=40103: Invalid authorization token signature readbody=true>
然而,这是令人困惑的部分。
如果我手动运行 get_service_bus_token() 函数中的步骤(即将它们复制并粘贴到IRB中),从而创建
$sb_token对象,如下所示:
$sb_token = "SharedAccessSignature sr=" + encoded + "&sig=" + ERB::Util.url_encode(hash) + "&se=" + ttl + "&skn=" + sasKeyName;
然后当我执行这些步骤,它的工作!!!
headers['Authorization'] = $sb_tokenresponse = HTTParty.post(url, :headers=>headers, :body=>body )
#<Net::HTTPCreated 201 Created readbody=true>
这让我很困惑。
本质上,生成
$sb_token**全局变量的函数似乎不能正确/准确地生成它,而如果我手动运行函数中的步骤,它会正确/准确地生成它。
这让我觉得是一个问题,要么a)全局变量的使用,要么b)在IRB提示符上创建函数vs内部生成的字符串是不同的。
有人有什么线索吗?

yh2wf1be

yh2wf1be1#

如果不了解应用程序的其余部分是如何构建的,很难确定。但是我可以告诉你,使用全局变量是一种不好的做法,可能会导致各种各样的问题,这些问题与你在这里描述的问题非常相似。你可以在这里和其他地方阅读有关ruby global variable问题的内容。
全局变量在多线程应用程序中的所有线程之间共享。如果您有两个线程同时运行,并且设置全局变量的值,那么您将遇到争用条件。例如,您在此方法的末尾设置$sb_token;如果两个线程同时调用这个方法,那么这个全局值将被最后一个运行的线程覆盖。Ruby线程调度可能意味着它按以下顺序执行:
1.第一个线程调用将$sb_token设置为值A的方法
1.第二个线程调用将$sb_token设置为值B的方法
1.第二个线程使用值为B的$sb_token运行后续方法
1.第一个线程使用值为B(不是A)的$sb_token运行后续方法
同样,你在方法开始时使用的变量很可能在应用程序的其他地方设置,它们也会遇到同样的问题。
在IRB中看不到这些错误的原因是因为IRB是单线程的,当只有一个线程时,不可能有并发问题。
我不能直接给予你如何在没有全局变量的情况下构造你的应用程序,因为我不知道它的其余部分是什么样子的,例如,如果你使用类和类示例。但通常你应该看看encapsulation作为指导。你可能想通过将变量用作方法的参数来封装它们,就像这样:

def get_service_bus_token(resourceUri, sasKeyName, sasKey)
  ...
end

或者将它们设置为示例变量:

def initialize
  @resouceUri = ...
  ...
end

def get_service_bus_token
  ...
  encoded = ERB::Util.url_encode(@resourceUri)
  ...
end

但作为最佳实践,你应该在几乎所有情况下避免使用全局变量和类变量,除非你清楚地了解它们的工作原理以及为什么需要使用它们。
最后,我建议你阅读链接中的Ruby样式指南。其中有一些技巧,你应该考虑遵循,以使你的代码更加地道,例如:
1.用于符号、方法和变量的Snake Case
1.我应该用;终止表达式吗?
1.压痕

相关问题