Faraday实现自定义HMAC授权:Ruby API封装认证失败问题排查
问题背景
我正在开发对接第三方API的Ruby封装库,该API使用的特殊授权逻辑暂无Faraday内置支持,需要自行实现授权头生成逻辑。官方文档给出的认证规则如下:
你的API凭证由公开客户端标识符(UUIDv4格式)和Base64编码的32字节私钥组成,组织级请求采用类Amazon风格的HMAC认证
官方给出的授权头构造规范如下:
Content-MD5: base64(md5(body)), RFC 1864 (binary md5) Content-Type: 'application/json' Date: 'Mon, 07 Dec 2015 22:57:52 +0200' (RFC 2822) Authorization: 'Success ' + client_identifier + ':' + base64( sha512_hmac( // returned as binary join( '\n', // unix newline, not the 2 character string [ http_verb, // 'POST' / 'GET' / etc. Content-MD5, // Same as header above. Include even for empty string body. Content-Type, // Same as header above. Can be empty. Date, // Same as header above. http_path // '/api/v1/document/?foo=bar' ] ), key // in binary, remember to decode base64 ) )
我目前编写的实现代码如下:
def create_authorization_header(path, payload) date = Date.today.rfc2822 md5_file = Digest::MD5.hexdigest(payload) content_md5 = Base64.strict_encode64(md5_file) digest = OpenSSL::Digest.new('sha512') autorization_header = "GET " + content_md5 + " application/json " + date + path autorization_header_enc = 'Success '+ identifier + ':' + Base64.strict_encode64(OpenSSL::HMAC.digest(digest, api_key, autorization_header)) connection.headers['Authorization'] = autorization_header_enc connection.headers['Content-MD5'] = content_md5 connection.headers['Content-type'] = "application/json" connection.headers['Date'] = date end
这段代码运行后始终无法通过API认证,找不到问题点,以下是可能的错误原因:
错误原因排查
- Content-MD5计算不符合规范:RFC 1864要求对MD5的二进制结果做Base64编码,当前代码使用
Digest::MD5.hexdigest得到的是十六进制字符串,再编码后结果完全不符合要求。正确写法为content_md5 = Base64.strict_encode64(Digest::MD5.digest(payload))。 - 签名字符串拼接规则错误:规范要求各个字段用Unix换行符
\n拼接,当前代码用空格拼接,直接不满足签名规则,需要把拼接的分隔符替换为\n。 - API密钥未做Base64解码:官方明确说明私钥是Base64编码的32字节内容,计算HMAC时需要先对
api_key做Base64解码得到二进制密钥,直接用原始Base64字符串作为密钥计算的结果肯定不匹配。 - 日期生成不符合要求:当前使用
Date.today生成的只有日期没有时分秒和时区信息,不符合RFC 2822要求的完整时间戳格式,应该替换为Time.now.rfc2822。 - HTTP动词硬编码:当前代码把请求方法硬写为
GET,如果实际请求是POST、PUT等其他方法,签名会直接不匹配,建议把请求方法作为参数传入动态拼接。 - 路径参数不完整:需要确认传入的
path包含完整的查询参数,类似示例中?foo=bar的部分不能遗漏,否则也会导致签名校验失败。 - 拼写问题(可选):如果代码运行报错,可检查是否是变量名
autorization_header拼写错误(正确应为authorization_header,少了字母h),如果运行无异常可忽略该问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

