使用Jquery在Last.fm进行身份验证 - 提供的方法签名无效

12

我正在尝试验证 Last.fm 会话并且在正确签署会话密钥的请求时遇到了困难。

我一直收到“提供了无效的方法签名”错误。但是当我在 JS 之外对我认为查询应该包含的内容进行 MD5 哈希处理时,我得到了相同的签名。 我想我可能在字符串中包含了错误的数据,但是找不出哪里错了。

我知道还有其他一些问题,我已经查看了所有这些问题,以查明出了什么问题,但我��誓它看起来对我来说是正确的。

这是签名算法和 Ajax 调用。我尝试留出足够的示例数据。

// Set elsewhere but hacked into this example:
var last_fm_data = {
    'last_token':'TOKEN876234876', 
    'user': 'bob',
    'secret': 'SECRET348264386'
};

// Kick it off.
last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});


// Low level API call, purely builds a POSTable object and calls it. 
function last_fm_call(method, data){  
    // param data - dictionary.

    last_fm_data[method] = false; 
    // Somewhere to put the result after callback.

    // Append some static variables
    data['api_key'] = "APIKEY1323454";
    data['format'] = 'json';
    data['method'] = method;
    post_data = last_fm_sign(data);

    $.ajax({
      type: "post",
      url: last_url,
      data: post_data,
      success: function(res){
          last_fm_data[method] = res;
          console.log(res['key'])// Should return session key.
      },
      dataType: 'json'
     });
}

function last_fm_sign(params){
    ss = "";
    st = [];
    so = {};
    Object.keys(params).forEach(function(key){
        st.push(key); // Get list of object keys
    });
    st.sort(); // Alphabetise it 
    st.forEach(function(std){
        ss = ss + std + params[std]; // build string
        so[std] = params[std];  // return object in exact same order JIC
    });    
        // console.log(ss + last_fm_data['secret']);
        // api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
    hashed_sec = unescape(encodeURIComponent($.md5(ss + last_fm_data['secret'])));
    so['signature'] = hashed_sec; // Correct when calculated elsewhere.
    return so; // Returns signed POSTable object
}

有什么我漏掉的吗?我完全被卡住了,不知道为什么不能返回一个按请求格式正确签名的POSTable对象 在这里。谢谢你的时间。

编辑:如果我没有得到任何建议,我就无法感谢任何人的时间!没有人有使用last.fm的经验吗?


1
尝试移除 data['format'] = 'json'; - George
谢谢,我会尝试这个方法和下面的答案。 - TechnicalChaos
谢谢,虽然有点偏离 - 我已经编辑了我的答案,附上我发现的关于格式属性的内容。 - TechnicalChaos
2个回答

5
在调查了您的代码和其他与last.fm api调用相关的帖子后,我发现@george lee实际上是正确的。在生成auth_sign时,您不需要提供format
除此之外,您需要对应用encodeURIComponent()unescape()函数后的auth_sign字符串应用$.md5()。像这样。
hashed_sec = $.md5(unescape(encodeURIComponent(ss + last_fm_data['secret'])));

同时,在进行 ajax 调用时,您需要将 api_key、token 和 api_sig 作为 data 传递。但是查看您的代码后发现,您正在传递 api_key、token、format、method 和 signature
因此,您需要从 ajax 调用的 data 字段中删除 format、method 和 signature
相反,您需要将 api_key、token 和 api_sig 传递到 data 字段中。
因此,在注释掉 data['format'] = 'json'; 行后,最终代码将如下所示。
    // Set elsewhere but hacked into this example:
    var last_fm_data = {
        'last_token':'TOKEN876234876', 
        'user': 'bob',
        'secret': 'SECRET348264386'
    };

    // Kick it off.
    last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});


    // Low level API call, purely builds a POSTable object and calls it. 
    function last_fm_call(method, data){  
        // param data - dictionary.
        last_fm_data[method] = false; 
        // Somewhere to put the result after callback.

        // Append some static variables
        data['api_key'] = "APIKEY1323454";
        //data['format'] = 'json';
        data['method'] = method;

        post_data = last_fm_sign(data);

        $.ajax({
          type: "POST",
          url: last_url,
          data: post_data,
          success: function(res){
              last_fm_data[method] = res;
              console.log(res['key'])// Should return session key.
          },
          dataType: 'json'
         });
    }

    function last_fm_sign(params){
        ss = "";
        st = [];
        so = {};
        so['api_key'] = params['api_key'];
        so['token'] = params['token'];
        Object.keys(params).forEach(function(key){
            st.push(key); // Get list of object keys
        });
        st.sort(); // Alphabetise it 
        st.forEach(function(std){
            ss = ss + std + params[std]; // build string
        });
        ss += last_fm_data['secret'];
            // console.log(ss + last_fm_data['secret']);
            // api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
        hashed_sec = $.md5(unescape(encodeURIComponent(ss)));
        so['api_sig'] = hashed_sec; // Correct when calculated elsewhere.
        return so; // Returns signed POSTable object
    }

请参考此链接。


谢谢!我会尽快尝试并告诉您结果。我已经尝试过仅使用该方法,但是它返回了XML响应而不是JSON,但我会尝试其他步骤并查看结果。 - TechnicalChaos
还没有机会测试这个,不幸的是。 - TechnicalChaos
感谢您的帮助,正是由于这里的示例,我才发现了代码中的错误。 - TechnicalChaos

3
因此,在测试一些响应时,我找到了解决方案。有两个问题。 编辑如下( 第一个是需要删除“


data['format'] = 'json';

正如George Lee所指出的,非常感谢George。
另一个问题是我错误地命名了一个变量,结果被POST到了错误的名称。这一行
so['signature'] = hashed_sec;

应该是
so['api_sig'] = hashed_sec;

我注意到 Pankaj 的回答中有这个问题,但很不幸他的回答(包括方法)都是错误的。做这两个更改可以解决调用并正确签名。
感谢所有的建议!
编辑: 经过一番尝试,我发现
data['format'] = 'json';

这是正确的,但它不会与签名一起进行哈希处理。 在哈希后添加 data['format'] = 'json'; 到 POST 对象中可行,并且在这种情况下将返回 JSON 而不是 XML - 这是首选方法。据我所知,在哈希后添加此代码没有任何记录,所以就是这样了。 新的工作代码如下所示,其中显示了用 -------------------- 标识的 2 行。

// Set elsewhere but hacked into this example:
var last_fm_data = {
    'last_token':'TOKEN876234876', 
    'user': 'bob',
    'secret': 'SECRET348264386'
};

// Kick it off.
last_fm_call('auth.getSession', {'token': last_fm_data['last_token']});


// Low level API call, purely builds a POSTable object and calls it. 
function last_fm_call(method, data){  
    // param data - dictionary.

    last_fm_data[method] = false; 
    // Somewhere to put the result after callback.

    // Append some static variables
    data['api_key'] = "APIKEY1323454";
    data['method'] = method;
    post_data = last_fm_sign(data);
    // THEN ADD THE FORMAT ---------------------------------------
    post_data['format'] = 'json';
    $.ajax({
      type: "post",
      url: last_url,
      data: post_data,
      success: function(res){
          last_fm_data[method] = res;
          console.log(res['key'])// Should return session key.
      },
      dataType: 'json'
     });
}

function last_fm_sign(params){
    ss = "";
    st = [];
    so = {};
    Object.keys(params).forEach(function(key){
        st.push(key); // Get list of object keys
    });
    st.sort(); // Alphabetise it 
    st.forEach(function(std){
        ss = ss + std + params[std]; // build string
        so[std] = params[std];  // return object in exact same order JIC
    });    
        // console.log(ss + last_fm_data['secret']);
        // api_keyAPIKEY1323454formatjsonmethodauth.getSessiontokenTOKEN876234876SECRET348264386
    hashed_sec = unescape(encodeURIComponent($.md5(ss + last_fm_data['secret'])));
    so['api_sig'] = hashed_sec; // RENAMED THIS ----------------------------
    return so; // Returns signed POSTable object
}

是的,我在 API 文档中确实看到它可以作为 JSON 返回,但没有找到如何执行的任何地方。不过很高兴你已经解决了! - George

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接