首页 文章

DocumentDB REST API - 授权令牌错误

提问于
浏览
3

Problem

每当我们请求列表或查询时,我们都会看到从DocumentDB REST API返回此错误,但是当我们按名称/ id获取对象时,我们看到错误:

输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 .

Background

我们已成功将node.js sdk与DocumentDB一起使用了一年多,但由于我们希望将后端的restful API代码从node.js App Service迁移到Azure Functions,我们看到10-30秒的滞后时间因为在一段时间内没有调用Function时,DocumentDB sdk加载缓慢 . 我们知道Function实例很热,并且这不是基于以前与Azure Functions团队通信的冷实例问题 .

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

Code

这是在本地node.js中运行的测试工具 . 一旦它运行,我们将把它移动到Azure功能 .

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 函数 .

密钥,应用程序名称和用户代理已被x替换为隐私/安全性 .

Test Results

列出数据库

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

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

响应:

“{\”code \“:\”Unauthorized \“,\”message \“:\”输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 . 服务器使用以下有效负载进行签名:'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 \ / \“,\” _用户\ “:\” 用户\ / \ “}”

列表集合

同样,从此数据库请求list of collections会返回令牌错误:

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

Respose:

“{\”code \“:\”Unauthorized \“,\”message \“:\”输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 . 服务器使用以下有效负载进行签名:'get \ ncolls \ ndbs / 00001 \ nsat,12 Aug 2017 12:32:19 gmt \ n \ n'\ r \ nActivityId:8a9d4ff8-24ef-4fd2-b400-f9f8aa743572 \“} “

获取收藏

但是当我打电话给get collection时,我得到了一个有效的回复:

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

响应:

“{\”id \“:\”00001 \“,\”indexingPolicy \“:{\”indexingMode \“:\”一致\“,\”自动\“:true,\”includedPaths \“:[{ \ “路径\”:\ “\ / * \”,\ “指数\”:[{\ “之类的\”:\ “范围\”,\ “数据类型\”:\ “号\”,\“精\ “:-1},{\” 样\ “:\” 范围\ “\ ”数据类型\“:\ ”字符串\“,\ ”精密\“: - 1},{\ ”样\“:\”空间\”,\ “数据类型\”:\ “点\”}]}],\ “excludedPaths \”:[]},\ “_ RID \”:\ “0eUiAJMAdQA = \” \ “_ TS \”:1454200014 ,\ “自\”:\ “DBS \ / 0eUiAA == \ / colls \ / 0eUiAJMAdQA = \ / \”,\ “ ETAG \”:\ “\” 00000100-0000-0000-0000-56ad54ce0000 \” \”,\ “_文档\”:\ “文档\ / \”,\ “_存储过程\”:\ “存储过程\ / \”,\ “_触发\”:\ “触发器\ / \”,\ “_的UDF \” :\ “的UDF \ / \”,\ “_冲突\”:\ “矛盾\ / \”}”

列出文件

在该集合上请求list documents给了我这个错误:

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

响应:

“{\”code \“:\”Unauthorized \“,\”message \“:\”输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 . 服务器使用以下有效负载进行签名:'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 == \“ ,\ “自\”:\ “DBS \ / 0eUiAA == \ / colls \ / 0eUiAJMAdQA = \ /文档\ / 0eUiAJMAdQCbHgAAAAAAAA == \ / \”,\ “ ETAG \”:\ “\” 0d00d1ee-0000- 0000-0000-598ef7d40000 \ “\” \ “附件\”:\ “附件\ / \”,\ “ 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 \“:\”输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 . 服务器使用以下有效负载进行签名:'post \ ndocs \ ndbs / 00001 / colls / 00001 \ nsat,12 Aug 2017 12:35:42 gmt \ n \ n'\ r \ nActivityId:b8b95f8c-1339-423e-b0e7-0d15d3056180 \“}”

1 回答

  • 5

    我认为文档不正确 . 他们说 resourceLink ,他们应该说 resource id . 如果您查看Node SDK代码,这就是他们计算授权标头的方式(请注意 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 变量使用空字符串 . 同样,如果要在数据库中列出集合,则链接实际上应该是数据库的ID(例如 dbs/00001 而不是 dbs/00001/colls ) .

相关问题