DocumentDB REST API - 授权令牌错误

DocumentDB REST API - Authorization Token Error

问题

每当我们请求列表或查询时,我们都会看到从 DocumentDB REST API 返回此错误,但当我们通过 name/id:

获取 objects 时则不会

The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used.

背景

我们已经成功地将 node.js sdk 与 DocumentDB 结合使用一年多了,但是由于我们想从node.js 到 Azure Functions 的应用程序服务我们看到 10-30 秒的延迟时间开始发挥作用,因为当函数有一段时间没有被调用时,DocumentDB sdk 加载缓慢。我们知道 Function 实例很热,根据之前与 Azure Functions 团队的沟通,这不是一个冷实例问题。

为了解决这个问题,我们想测试 DocumentDB REST API,它需要零个外部库到 node.js 函数中的 运行 并且应该尽快执行。

代码

这是本地 node.js 中的测试工具 运行ning。一旦它开始工作,我们会将其移至 Azure Functions。

var express = require('express');
var router = express.Router();
var crypto = require("crypto"); 
var request = require('request');

router.get('/', function (req, res, next) {

  var key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
  var uri = "https://xxxxxx.documents.azure.com";

  var verb = 'GET';
  var type = 'dbs';
  var link = 'dbs';
  var url = `${uri}/${link}`;

  var headers = getDefaultRequestHeaders();

  // var body = `{"query":"SELECT * FROM c", "parameters": []}`;
  var body = '';

  headers['content-length'] = body.length;
  headers['authorization'] = getAuthorizationTokenUsingMasterKey(verb, type, link, headers['x-ms-date'], key);

  request[verb.toLowerCase()]({"url": url, "headers": headers, "body": body}, function (error, response, body) {

    // console.log(`error is ${error}`);
    // console.log(`response is ${JSON.stringify(response, null, 2)}`);
    console.log(`body is ${body}`);

    res.status(response.statusCode).json(body);

  });

});

function getDefaultRequestHeaders(isQuery, date) {

  var headers = {
    "content-type": "application/json", 
    "x-ms-date": new Date().toUTCString(),
    "x-ms-version": "2017-02-22",
    "accept": "application/json",
    "cache-control": "no-cache",
    "user-agent": "xxxxxx/1.0"
  };

  if(isQuery) {
    headers["x-ms-documentdb-isquery"] = true;
    headers["content-type"] = "application/query+json";
  }

  if(date) {
    headers["x-ms-date"] = date;
  }

  return headers;

}

function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceLink, date, masterKey) {  
    var key = new Buffer(masterKey, "base64");  

    var text = (verb || "").toLowerCase() + "\n" +   
               (resourceType || "").toLowerCase() + "\n" +   
               (resourceLink || "") + "\n" +   
               date.toLowerCase() + "\n" +   
               "" + "\n";  

    var body = new Buffer(text, "utf8");  
    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");  

    var MasterToken = "master";  

    var TokenVersion = "1.0";  

    return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);  
}  


module.exports = router;

我们正在逐字使用 Access control in the DocumentDB API 页面中的 getAuthorizationTokenFromMasterKey 函数。

密钥、应用程序名称和 user-agent 已替换为 privacy/security 的 x。

测试结果

列出数据库

当我尝试对 list dbs 服务器进行最基本的调用时 returns 令牌错误:

  var verb = 'GET';
  var type = 'dbs';
  var link = 'dbs';

回复:

"{\"code\":\"Unauthorized\",\"message\":\"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'get\ndbs\n\nsat, 12 aug 2017 12:28:41 gmt\n\n'\r\nActivityId: acbf19d9-6485-45c5-9c30-6aa21f14d5b3\"}"

获取数据库

然而,当我执行 get database 请求时它工作正常:

  var verb = 'GET';
  var type = 'dbs';
  var link = 'dbs/00001';

响应:

"{\"id\":\"00001\",\"_rid\":\"0eUiAA==\",\"_ts\":1441256154,\"_self\":\"dbs\/0eUiAA==\/\",\"_etag\":\"\"00007d4a-0000-0000-0000-55e7d2da0000\"\",\"_colls\":\"colls\/\",\"_users\":\"users\/\"}"

列表Collections

同样,从该数据库请求 list of collections returns 令牌错误:

var verb = 'GET';
var type = 'colls';
var link = 'dbs/00001/colls';

回复:

"{\"code\":\"Unauthorized\",\"message\":\"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'get\ncolls\ndbs/00001\nsat, 12 aug 2017 12:32:19 gmt\n\n'\r\nActivityId: 8a9d4ff8-24ef-4fd2-b400-f9f8aa743572\"}"

得到Collection

但是当我调用 get collection 时,我得到了一个有效的响应:

var verb = 'GET';
var type = 'colls';
var link = 'dbs/00001/colls/00001';

回复:

"{\"id\":\"00001\",\"indexingPolicy\":{\"indexingMode\":\"consistent\",\"automatic\":true,\"includedPaths\":[{\"path\":\"\/*\",\"indexes\":[{\"kind\":\"Range\",\"dataType\":\"Number\",\"precision\":-1},{\"kind\":\"Range\",\"dataType\":\"String\",\"precision\":-1},{\"kind\":\"Spatial\",\"dataType\":\"Point\"}]}],\"excludedPaths\":[]},\"_rid\":\"0eUiAJMAdQA=\",\"_ts\":1454200014,\"_self\":\"dbs\/0eUiAA==\/colls\/0eUiAJMAdQA=\/\",\"_etag\":\"\"00000100-0000-0000-0000-56ad54ce0000\"\",\"_docs\":\"docs\/\",\"_sprocs\":\"sprocs\/\",\"_triggers\":\"triggers\/\",\"_udfs\":\"udfs\/\",\"_conflicts\":\"conflicts\/\"}"

列出文件

在那个 collection 上请求 list documents 给我这个错误:

var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';

回复:

"{\"code\":\"Unauthorized\",\"message\":\"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'get\ndocs\ndbs/00001/colls/00001\nsat, 12 aug 2017 12:34:48 gmt\n\n'\r\nActivityId: 57097e95-c41b-4770-b91a-370418ef2cce\"}"

获取文档

毫不奇怪,获取 single document 工作正常:

var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs/e7fe638d-2152-2097-f9c6-9801d7cf5cdd';

回复:

"{\"name\":\"test rest api\",\"id\":\"e7fe638d-2152-2097-f9c6-9801d7cf5cdd\",\"_rid\":\"0eUiAJMAdQCbHgAAAAAAAA==\",\"_self\":\"dbs\/0eUiAA==\/colls\/0eUiAJMAdQA=\/docs\/0eUiAJMAdQCbHgAAAAAAAA==\/\",\"_etag\":\"\"0d00d1ee-0000-0000-0000-598ef7d40000\"\",\"_attachments\":\"attachments\/\",\"_ts\":1502541779}"

查询文档

最后,发送 query 也会导致令牌错误:

var verb = 'POST';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';
var body = `{"query":"SELECT * FROM c", "parameters": []}`;

回复:

"{\"code\":\"Unauthorized\",\"message\":\"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndocs\ndbs/00001/colls/00001\nsat, 12 aug 2017 12:35:42 gmt\n\n'\r\nActivityId: b8b95f8c-1339-423e-b0e7-0d15d3056180\"}"

我认为文档不正确。在他们说 resourceLink 的地方,他们实际上应该说 resource id。如果您查看 Node SDK 代码,这就是他们计算授权的方式 header(注意 resourceId 的使用):

getAuthorizationTokenUsingMasterKey: function (verb, resourceId, resourceType, headers, masterKey) {
    var key = new Buffer(masterKey, "base64");

    var text = (verb || "").toLowerCase() + "\n" +
               (resourceType || "").toLowerCase() + "\n" +
               (resourceId || "") + "\n" +
               (headers["x-ms-date"] || "").toLowerCase() + "\n" +
               (headers["date"] || "").toLowerCase() + "\n";

    var body = new Buffer(text, "utf8");

    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");

    var MasterToken = "master";

    var TokenVersion = "1.0";

    return "type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature;
},

因此,如果您想列出数据库,因为没有资源 ID,您需要为 link 变量使用空字符串。同样,如果你想在数据库中列出 collections,link 实际上应该是数据库的 id(例如 dbs/00001 而不是 dbs/00001/colls)。

我遇到了同样的问题。对于查询文档,我收到了授权令牌错误。是因为错误 ResourceId/ResourceLink

var verb = 'POST';
var type = 'docs';
var link = 'dbs/{db-id}/colls/{coll-id}/docs';
var url = `${uri}/${link}`;
var resourceLink = "dbs/{db-id}/colls/{coll-id}"

getAuthorizationTokenUsingMasterKey(verb, type, resourceLink, headers['x-ms-date'], key)

给定问题数据中唯一需要更正的是在生成 AuthorizationToken 时更改适当的 resourceLink。对于查询文档,资源链接是 而不是

我想提供另一件事来解决这个问题。在我的例子中,我必须添加这个 header: x-ms-documentdb-query-enablecrosspartition: true,因为我用 partitionKey.

创建了我的容器

我还想确认如何设置我的主要参数来计算授权 header 以查询文档:

resourceType: docs
resourceLink: dbs/<databaseId>/colls/<containerId>

到目前为止,我一直认为 resourceLInk 必须与请求相匹配 URL 但这表明我错了。同样注意 resourceLink 中不存在 resourceType。

POST /dbs/<databaseId>/colls/<containerId>/docs HTTP/1.1
accept: application/json
x-ms-documentdb-isquery: true
x-ms-version: 2018-12-31
authorization: type%3Dmaster%26ver%3D1.0%26sig%***********************
x-ms-date: Sat, 03 Apr 2021 22:34:24 GMT
x-ms-documentdb-query-enablecrosspartition: true
x-correlation-id: be1b1fe1-94cc-11eb-a0a4-38f9d3924940
Host: <host>.documents.azure.com
User-Agent: AHC/1.0
Connection: keep-alive
Content-Type: application/query+json
Content-Length: 72

{
  "query": "SELECT * FROM <containerId>",
  "parameters": [
    
  ]
}

我在更新文档数据库时遇到了同样的错误,但就我而言,我意识到我使用的是只读键。更改连接字符串以将其用于读写密钥后,我能够更新记录。