Node.js中使用http.client进行摘要式身份validation的问题

我试着在使用http.get的时候实现摘要请求, 每次都得到“ 摘要authentication失败 ”的消息:(

var hashlib = require('hashlib'), http = require('http'), url = require('url'), qs = require('querystring'), hashlib = require('hashlib'); var username = 'user'; var password = 'pass'; var options = { 'host' : 'username.livejournal.com', 'path' : '/data/rss?auth=digest' }; http.get(options, function(res) { res.setEncoding('utf-8'); // got 401, okay res.on('data', function(chunk) { var authResponseParams = qs.parse(res.headers['www-authenticate'].substr(7), ', '); // cut "Digest " var ha1 = hashlib.md5(username + ':' + authResponseParams.realm + ':' + password); var ha2 = hashlib.md5('GET:' + options.path); var response = hashlib.md5(ha1 + ':' + authResponseParams.nonce + ':1::auth:' + ha2); var authRequestParams = { 'username' : username, 'realm' : authResponseParams.realm, 'nonce' : authResponseParams.nonce, 'uri' : options.path, 'qop' : authResponseParams.qop, 'nc' : '1', 'cnonce' : '', 'response' : response }; options.headers = { 'Authorization' : 'Digest ' + qs.stringify(authRequestParams, ',') }; http.get(options, function(res) { res.setEncoding('utf-8'); res.on('data', function(chunk) { console.log(chunk); }); }); }); }).on('error', function(e) { console.log('Got error: ' + e.message); }); 

这个代码有什么问题?

几件事情:

  • res.on('data',fn)中的callback不一定被调用,因为响应不一定包含正文,只有标题。 所以用res.on('end',fn)来代替。
  • 摘要头文件parsing导致了一个非常奇怪的对象,因为参数可以被引用,并且可以包含空格(被转义)。
  • 写入Authentication标头的作用相同。

这是一个适合我的版本:

 var hashlib = require('hashlib'), http = require('http'), _ = require('underscore') var username = 'user'; var password = 'pwd'; var options = { 'host' : 'host', 'path' : '/path' }; http.get(options, function(res) { res.setEncoding('utf-8'); res.on('end', function() { var challengeParams = parseDigest(res.headers['www-authenticate']) var ha1 = hashlib.md5(username + ':' + challengeParams.realm + ':' + password) var ha2 = hashlib.md5('GET:' + options.path) var response = hashlib.md5(ha1 + ':' + challengeParams.nonce + ':1::auth:' + ha2) var authRequestParams = { username : username, realm : challengeParams.realm, nonce : challengeParams.nonce, uri : options.path, qop : challengeParams.qop, response : response, nc : '1', cnonce : '', } options.headers = { 'Authorization' : renderDigest(authRequestParams) } http.get(options, function(res) { res.setEncoding('utf-8') var content = '' res.on('data', function(chunk) { content += chunk }).on('end', function() { console.log(content) }) }); }); }) function parseDigest(header) { return _(header.substring(7).split(/,\s+/)).reduce(function(obj, s) { var parts = s.split('=') obj[parts[0]] = parts[1].replace(/"/g, '') return obj }, {}) } function renderDigest(params) { var s = _(_.keys(params)).reduce(function(s1, ii) { return s1 + ', ' + ii + '="' + params[ii] + '"' }, '') return 'Digest ' + s.substring(2); } 

无法npm install hashlib ,我使用Node中的Crypto模块来创buildmd5散列。

var ha1 = crypto.createHash('md5').update(new Buffer(username + ':' + challengeParams.realm + ':' + password)).digest('base64');