不,Digest Access Authentication Scheme 有点复杂,因为它实现了需要以下步骤的 challenge-response authentication mechanism:
- 客户端发送访问受保护资源的请求,但未发送可接受的授权头字段
- 服务器以“401 Unauthorized”状态码和 WWW-Authenticate 标头字段(digest-challenge)响应
- 客户端针对同一资源发送另一个请求,但包含 Authorization 标头字段以响应挑战(digest-response)
- 如果授权不成功,转步骤2;否则服务器正常运行。
这意味着至少有两个请求/响应对。
每个WWW-Authenticate response header field 的语法如下:
challenge = "Digest" digest-challenge
digest-challenge = 1#( realm | [ domain ] | nonce |
[ opaque ] |[ stale ] | [ algorithm ] |
[ qop-options ] | [auth-param] )
因此,您需要解析 digest-challenge 以获取能够为 Authorization request header field 生成 digest-reponse 的参数,语法如下:
credentials = "Digest" digest-response
digest-response = 1#( username | realm | nonce | digest-uri
| response | [ algorithm ] | [cnonce] |
[opaque] | [message-qop] |
[nonce-count] | [auth-param] )
该部分还描述了如何计算 digest-response 参数。特别是,您可能需要一个 MD5 实现,因为这是此身份验证方案最常用的算法。
这是一个简单的标记化,您可以从这里开始:
var ws = '(?:(?:\\r\\n)?[ \\t])+',
token = '(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2E\\x30-\\x39\\x3F\\x41-\\x5A\\x5E-\\x7A\\x7C\\x7E]+)',
quotedString = '"(?:[\\x00-\\x0B\\x0D-\\x21\\x23-\\x5B\\\\x5D-\\x7F]|'+ws+'|\\\\[\\x00-\\x7F])*"',
tokenizer = RegExp(token+'(?:=(?:'+quotedString+'|'+token+'))?', 'g');
var tokens = xhr.getResponseHeader("WWW-Authentication").match(tokenizer);
这将变成一个 WWW-Authenticate 标头字段,例如:
WWW-Authenticate: Digest
realm="testrealm@host.com",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
进入:
['Digest', 'realm="testrealm@host.com"', 'qop="auth,auth-int"', 'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093"', 'opaque="5ccc069c403ebaf9f0171e9517f40e41"']
然后您需要解析参数(检查存在和有效性)并提取值。请注意,quoted-string 值可以折叠,因此您需要展开它们(另请参阅 RFC 中使用 unquote 函数 unq):
function unq(quotedString) {
return quotedString.substr(1, quotedString.length-2).replace(/(?:(?:\r\n)?[ \t])+/g, " ");
}
有了这个,你应该能够自己实现它。