我正在尝试使用来自 gathercontent.com 的 API 获得一个简单的(!)摘要身份验证与 Node js 一起工作。
一切似乎都正常,除了我仍然收到如下所示的“错误凭据”响应:
{ success: false, error: 'Wrong Credentials!' }
代码如下所示:
var https = require('https'),
qs = require('querystring');
apikey = "[my api key goes in here]",
pwd = "[my password goes in here]",
crypto = require('crypto');
module.exports.apiCall = function () {
var options = {
host:'abcdefg.gathercontent.com',
port:443,
path:'/api/0.1/get_pages_by_project/get_me',
method:'POST',
headers:{
"Accept":"application/json",
"Content-Type":"application/x-www-form-urlencoded"
}
};
var req = https.request(options, function (res) {
res.on('data', function (d) {
var creds = JSON.parse(d);
var parsedDigest = parseDigest(res.headers['www-authenticate']);
console.log(parsedDigest);
var authopts = {
host:'furthercreative.gathercontent.com',
port:443,
path:'/api/0.1/get_pages_by_project/get_me',
method:'POST',
headers:{
"Accept":"application/json",
"Content-Type":"application/x-www-form-urlencoded",
"Authorization" : getAuthHeader(parsedDigest, apikey, parsedDigest['Digest realm'], pwd)
}
};
console.log(authopts);
console.log('\n\n\n');
var req2 = https.request(authopts, function (res2) {
console.log("statusCode: ", res2.statusCode);
console.log("headers: ", res2.headers);
res2.on('data', function (d2) {
var result = JSON.parse(d2);
});
});
req2.end();
});
});
req.write('id=1234');
req.end();
req.on('error', function (e) {
console.error(e);
});
};
function parseDigest(s){
var parts = s.split(',');
var obj = {};
var nvp = '';
for(var i = 0; i < parts.length; i++){
nvp = parts[i].split('=');
obj[nvp[0]] = nvp[1].replace(/"/gi, '');
}
return obj;
}
function getAuthHeader(digest, apikey, realm, pwd){
var md5 = crypto.createHash('md5');
var s = '';
var nc = '00000001';
var cn = '0a4f113b';
var HA1in = apikey+':'+realm+':'+pwd;
md5 = crypto.createHash('md5');
md5.update(HA1in);
var HA1out = md5.digest('hex');
var HA2in = 'POST:/api/0.1/get_pages_by_project/get_me';
md5 = crypto.createHash('md5');
md5.update(HA2in);
var HA2out = md5.digest('hex');
md5 = crypto.createHash('md5');
var respIn = HA1out + ':' + digest.nonce + ':'+nc+':'+cn+':'+digest.qop+':'+ HA2out;
md5.update(respIn);
var resp = md5.digest('hex');
s = [ 'Digest username="',apikey,'", ',
'realm="',digest['Digest realm'],'", ',
'nonce="',digest.nonce,'", ',
'uri="/api/0.1/get_pages_by_project/get_me", ',
'cnonce="',cn,'", ',
'nc="',nc,'", ',
'qop="',digest.qop,'", ',
'response="',resp,'", ',
'opaque="',digest.opaque,'"'].join('')
return s;
}
我会尝试 Curl 到它,但我不确定该怎么做!
感谢任何帮助!
最佳答案
我发现有几个问题可能与您的问题有关。很难说出哪些是真正的罪魁祸首,因为对 gathercontent 的实现一无所知。如果您粘贴了他们的“WWW-Authenticate” header 的示例,那么提供具体帮助会容易得多。
所以我推测实际原因是什么,但这里有一些您无论如何都应该解决的实际问题,以符合规范(即防止它在将来因为服务器开始做事略有不同而中断):
- 在
Authorization
在您创建的 header 中,删除双引号nc
,也许还有qop
- 我不知道是什么
qop
值 gathercontent 正在使用。如果是auth-int
,那么您还必须将散列的 HTTP 正文附加到HA2
, 请参阅 #3.2.2.3 of the spec - 此外,他们可能会指定逗号分隔的 qop 值列表供您选择 - 或者服务器可能不会发送qop
的值|完全,即他们使用最基本的 HTTP 摘要身份验证,其中您的实现将违反 spec ,因为那时你不被允许,例如发送cnonce
,nc
等 - 你尝试通过
parsedDigest['Digest realm']
获取领域,即 您假设realm
是初始Digest
之后的第一个属性 关键字。这可能是也可能不是这种情况,但您不应该依赖它(修改您的parseDigest
函数以在拆分其余部分之前剥离字符串"Digest "
) - 你使用的方式
parsedDigest
,您假设 Digest 始终以这种方式大写,并且realm
,nonce
等 总是小写。根据规范,这些都是不区分大小写
几个不相关的问题:
- 服务器真的强制你使用
Digest authentication
吗? ?这是 HTTPS,所以你不妨做Basic authentication
,它更容易,并且使用 HTTPS,同样安全。 (在查看 gathercontent 后在这里回答自己:基本身份验证显然是 not possible ) - 正如我在对您的问题的评论中提到的,
cnonce
每个请求应该是随机的,特别是,你不应该从 Wikipedia 复制和粘贴它,这让你更容易受到攻击(但这里不是问题,因为在你的情况下所有数据都通过 SSL)
关于如何 curl 它 - 试试这个:
curl --data 'id=1234' --digest --user "apikey:pwd" https://abcdefg.gathercontent.com:443/api/0.1/get_pages_by_project/get_me
关于http - 无法获得摘要身份验证以使用 node.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12850646/