6

在 Houndify API Docs for Authentication 中,您有以下内容块:


验证请求的示例

假设我们有以下信息:

UserID: ae06fcd3-6447-4356-afaa-813aa4f2ba41
    RequestID: 70aa7c25-c74f-48be-8ca8-cbf73627c05f
    Timestamp: 1418068667   
    ClientID: KFvH6Rpy3tUimL-pCUFpPg==
    ClientKey: KgMLuq-k1oCUv5bzTlKAJf_mGo0T07jTogbi6apcqLa114CCPH3rlK4c0RktY30xLEQ49MZ-C2bMyFOVQO4PyA==
  1. 按以下格式连接 UserID 字符串、RequestID 字符串和 TimeStamp 字符串:{user_id};{request_id}{timestamp}

  2. 使用示例中的值,在这种情况下,预期的输出将是:ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f1418068667

  3. 使用解码的 ClientKey 对消息进行签名。结果是一个 32 字节的二进制字符串(我们无法直观地表示)。然而,在 base-64 编码之后,签名是:myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=

  4. 然后客户端生成两个身份验证标头Hound-Request-AuthenticationHound-Client-Authentication

  5. Hound-Request-Authentication 标头由以下格式的 UserID 和 RequestID 连接而成:{user-id};{request-id}. 继续上面的示例,此标头的值将是:Hound-Request-Authentication:ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f

  6. Hound-Client-Authentication 标头由以下格式的 ClientID、TimeStamp 字符串和签名组成:{client-id};{timestamp};{signature}. 继续上面的示例,此标头的值将是:Hound-Client-Authentication: KFvH6Rpy3tUimL-pCUFpPg==;1418068667;myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=


对于数字 3,它显示“使用解码的 ClientKey 签署消息”。“message”和“ClientKey”是两个不同的字符串。

我的问题:你如何用另一个字符串签署一个字符串,即这到底是什么意思?你将如何在 JavaScript 中做到这一点?

var message = 'my_message';
var key = 'signing_key';

//??what next??

我试图弄清楚这一切,以便我可以在 Postman 中创建一个预请求脚本来执行正确的 HmacSHA256 哈希。

4

2 回答 2

7

根据文档,如果您使用他们的 SDK 之一,它将自动验证您的请求:

SDK 已经为您处理身份验证。您只需向 SDK 提供在创建客户端时为其生成的客户端 ID 和客户端密钥。如果您不使用 SDK,请使用右侧的代码示例生成您自己的 HTTP 标头来验证您的请求。

但是,如果您想手动执行此操作,我相信您需要计算他们在问题链接中描述的字符串的HMAC值,然后将其作为Hound-Client-Authentication请求标头的一部分进行 base64 编码发送。他们为 node.js 提供了一个示例

var uuid = require('node-uuid');
var crypto = require('crypto');

function generateAuthHeaders (clientId, clientKey, userId, requestId) {

    if (!clientId || !clientKey) {
        throw new Error('Must provide a Client ID and a Client Key');
    }

    // Generate a unique UserId and RequestId.
    userId      = userId || uuid.v1();

    // keep track of this requestId, you will need it for the RequestInfo Object
    requestId   = requestId || uuid.v1();

    var requestData = userId + ';' + requestId;

    // keep track of this timestamp, you will need it for the RequestInfo Object
    var timestamp   = Math.floor(Date.now() / 1000),  

        unescapeBase64Url = function (key) {
            return key.replace(/-/g, '+').replace(/_/g, '/');
        },

        escapeBase64Url = function (key) {
            return key.replace(/\+/g, '-').replace(/\//g, '_');
        },

        signKey = function (clientKey, message) {
            var key = new Buffer(unescapeBase64Url(clientKey), 'base64');
            var hash = crypto.createHmac('sha256', key).update(message).digest('base64');
            return escapeBase64Url(hash);

        },

        encodedData = signKey(clientKey, requestData + timestamp),
        headers = {
            'Hound-Request-Authentication': requestData,
            'Hound-Client-Authentication': clientId + ';' + timestamp + ';' + encodedData
        };

    return headers;
};
于 2016-02-05T16:11:59.643 回答
3

所以基本上,签名 [在这种特定情况下] 只是意味着使用除了key之外的散列算法创建字符串的散列,而不是无键散列 [如 MD5]。例如:

var message = 'my_message';
var key = 'signing_key';
var hashed_message = hash_func(message, key);

其中 hash_func 是一个像 HmacSHA256 的散列算法(有问题的散列算法)。

我试图弄清楚这一点的原因是使用 Postman 测试 Houndify API 的身份验证。幸运的是,Postman 有一个很好的功能,称为预请求脚本[完整的哈希算法],如果您需要预生成需要随请求一起发送的值,它会有所帮助。

经过一番折腾,我设法创建了一个预请求脚本,可以正确地验证这个 API(见下面的代码)。

var unescapeBase64Url = function (key) {
            return key.replace(/-/g, '+').replace(/_/g, '/');
        },

        escapeBase64Url = function (key) {
            return key.replace(/\+/g, '-').replace(/\//g, '_');
        },
        guid = function() {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
        s4() + '-' + s4() + s4() + s4();
    };

var client_id_str = environment["client-id"];
var client_key_str = environment["client-key"];
var user_id_str = environment["user-id"];
var request_id_str = guid();
var timestamp_str = Math.floor(Date.now() / 1000);

var client_key_dec_str = CryptoJS.enc.Base64.parse(unescapeBase64Url(client_key_str));

var message_str = user_id_str+";"+request_id_str+timestamp_str;
var signature_hash_obj = CryptoJS.HmacSHA256(message_str, client_key_dec_str);
var signature_str = signature_hash_obj.toString(CryptoJS.enc.Base64);

var hound_request_str = user_id_str+";"+request_id_str;
var hound_client_str = client_id_str+";"+timestamp_str+";"+escapeBase64Url(signature_str);

postman.setEnvironmentVariable("hound-request-authentication", hound_request_str);
postman.setEnvironmentVariable("hound-client-authentication", hound_client_str);

请注意,您将必须在 Postman 中为client-idclient-keyuser-id创建环境变量,以及为头变量hound-request-authenticationhound-client-authentication创建最终值定义标题时将引用它。

希望能帮助到你。

于 2016-02-06T01:34:33.543 回答