basic 认证形式
请求示例如下,主要是Authorization头(位置不重要,http头一般都不分先后)
GET /GetDeviceInfo HTTP/1.1 Host: 192.168.220.128 Authorization: Basic YWRtaW46MTIzNDU2 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept-Encoding: gzip, deflate Accept: */* Cache-Control: no-cache Cookie: Secure Connection: closebasic认证方式(前边请求Authorization头的YWRtaW46MTIzNDU2,实际上是用户名admin密码123456使用以下计算方法得到)
var authHeader = "Basic " + new Buffer(options.user + ":" + options.pass).toString("base64");gigest 认证形式
请求直接返回401 内容为
// 主要需要的内容是 WWW-Authenticate 服务器根据请求自动生成的 const r = [ "HTTP/1.1 401 Unauthorized", 'WWW-Authenticate: Digest realm="Login to f5c8557f6bee8548b0d72a1c30780e5e", qop="auth", nonce="1189347886", opaque="d6ae186150aa54aa82e816e281102905e064907f"', "Connection: close", "Set-Cookie:secure; HttpOnly", "CONTENT-LENGTH: 0", "", "", ];拿到返回值 根据特定组合编码放置下次请求 Authorization
GET /GetDeviceInfo HTTP/1.1 Host: 192.168.220.128 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0 Authorization: Digest username="admin",realm="TVT API Test Tool",nonce="d4f95e85dc5a39a4914db61b67878f5b",uri="GetDeviceInfo",algorithm="MD5",cnonce="d4f95e85dc5a39a4914db61b67878f5b",nc=00000001,qop="auth",response="1cc4cf126d3c4a70d2de34c5d8c2943c" Accept-Encoding: gzip, deflate Accept: */* Cache-Control: no-cache Cookie: Secure Connection: close // 注意 - 是返回值有的 - XXX 是需要自己处理的值 // username----系统用户名;客户端自行填充 - admin // realm----领域;服务端通过WWW-Authenticate头返回内容可以自己随便定,但其目的是用于提示客户端当前是什么系统,所以规范来说应类似于“myhost@testrealm.com”的形式。 - // nonce----服务端通过WWW-Authenticate头返回的随机数 - // uri----请求接口或资源(似乎规范来说应用GET或POST后的一样,上边例子中少了/是因为服务端没按规范实现)- GetDeviceInfo // algorithm----后边response用的计算方法 - MD5 // cnonce----client nonce,客户端生成的随机数 - uuid // nc----nonce count,用于标识进行请求的次数。(但你一直不变服务端也不会管你对不对)- 00000001 // qop----quality of protection,进一步限定response的计算方法,服务端通过WWW-Authenticate头返回。 - // response----认证最主要的值,前面各字段除algorithm外全要参与该值的计算。认证计算方式
在最开始的RFC 2069中规定response计算方法如下:
HA1 = MD5(username:realm:password) HA2 = MD5(method:uri) response = MD5(HA1:nonce:HA2)随后的RFC 2617对计算方法进行了增强,规定计算方法如下(当algorithm值为MD5或未指定、qop未指定时等同RFC 2069
# HA1部分 # 当algorithm值为"MD5"或未指定时,HA1计算方法如下 HA1 = MD5(username:realm:password) # 当algorithm值为"MD5-sess"时,HA1计算方法如下 HA1 = MD5(MD5(username:realm:password):nonce:cnonce) # HA2部分 # 当qop值为"auth"或未指定时,HA2计算方法如下 HA2 = MD5(method:uri) # 当qop值为"auth-int"时,HA2计算方法如下;entityBody是指整个body(?) HA2 = MD5(method:uri:MD5(entityBody)) # response部分 # 当qop值为"auth"或"auth-int"时,response计算方法如下 response = MD5(HA1:nonce:nonceCount:cnonce:qop:HA2) # 当qop未指定时,response计算方法如下 response = MD5(HA1:nonce:HA2)nodejs 编写测试文件 测试组合
/* * @Author: 周凯 * @Date: 2020-10-20 14:31:24 * @LastEditTime: 2020-10-20 15:46:06 */ const r = [ "HTTP/1.1 401 Unauthorized", 'WWW-Authenticate: Digest realm="Login to f5c8557f6bee8548b0d72a1c30780e5e", qop="auth", nonce="1189347886", opaque="d6ae186150aa54aa82e816e281102905e064907f"', "Connection: close", "Set-Cookie:secure; HttpOnly", "CONTENT-LENGTH: 0", "", "", ]; const md5 = require("md5"); const { v4 } = require("uuid"); const data = r[1]; console.log(generateAuthorization(data, "admin", "a12345678")); function generateAuthorization(data, username, password) { // 最终结果值 const endParams = { realm: "", qop: "", nonce: "", opaque: "", cnonce: v4().replace(/-/gi, ""), nc: "00000001", }; console.log("data", data); console.log("\n"); const rr = data.replace("WWW-Authenticate", "Authenticate"); rr.split(",").forEach((item) => { let r = item.trim().replace(/=/gi, ":"); if (foramtParams(r, "realm:")) endParams.realm = foramtParams(r, "realm:"); if (foramtParams(r, "qop:")) endParams.qop = foramtParams(r, "qop:"); if (foramtParams(r, "nonce:")) endParams.nonce = foramtParams(r, "nonce:"); if (foramtParams(r, "opaque:")) endParams.opaque = foramtParams(r, "opaque:"); }); /** * 获取参数时的处理 * @param {*} data 数据 * @param {*} val 选择搜索的值 */ function foramtParams(data, val) { if (data.indexOf(val) !== -1 || data.indexOf(val) === 0) { return data.substring(data.indexOf(val) + val.length).replace(/"/gi, ""); } return false; } // HA1部分 const HA1 = md5(`${username}:${endParams.realm}:${password}`); // HA2 const HA2 = md5("GET:GetDeviceInfo"); const response = md5( `${HA1}:${endParams.nonce}:${endParams.nc}:${endParams.cnonce}:${endParams.qop}:${HA2}` ); const returnValidationHeader = `Authorization: Digest username="${username}",realm="${endParams.realm}",nonce="${endParams.nonce}",uri="GetDeviceInfo",algorithm="MD5",cnonce="${endParams.cnonce}",nc="${endParams.nc}",qop="${endParams.qop}",response="${response}"`; return returnValidationHeader; }