通过REST在DocumentDb中创建文档时未经授权

问题描述:

我正在使用.NET Core,因此无法使用Azure DocumentDb SDK。这就是为什么我想通过REST界面创建文档的原因。我设法查询数据库,但是当我POST一个JSON文档时,我得到一个未经授权的响应。这是我的代码:通过REST在DocumentDb中创建文档时未经授权

const string DatabaseId = "DB-id"; 
const string CollectionId = "UserSettings"; 
var documentDbUrl = "Injected via DI"; 
var authorizationKey = "Also injected; 

using (var httpClient = new HttpClient()) 
{ 
    var utcNow = DateTime.UtcNow; 
    httpClient.DefaultRequestHeaders.Add("x-ms-date", utcNow.ToString("r")); 
    httpClient.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06"); 
    httpClient.DefaultRequestHeaders.Add("x-ms-documentdb-is-upsert", "true"); 

    var resourceLink = string.Format("dbs/{0}/colls/{1}/docs", DatabaseId, CollectionId); 
    var baseUrl = new Uri(documentDbUrl); 

    var masterKeyAuthorizationSignatureGenerator = new MasterKeyAuthorizationSignatureGenerator(); 
    var authHeader = masterKeyAuthorizationSignatureGenerator.Generate("POST", resourceLink, "docs", authorizationKey, "master", "1.0", utcNow); 
    httpClient.DefaultRequestHeaders.Add("authorization", authHeader); 

    var response = await httpClient.PostAsJsonAsync(new Uri(baseUrl, resourceLink), userSettings); 

    // at this point, response.StatusCode is Unauthorized 
} 

MasterKeyAuthorizationSignatureGenerator你看到没有包含the logic to create the hash,查询数据库时的工作原理:

public string Generate(string verb, string resourceId, string resourceType, string key, string keyType, string tokenVersion, DateTime requestDateTime) 
{ 
    var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) }; 

    var payLoad = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}\n{1}\n{2}\n{3}\n{4}\n", 
      verb.ToLowerInvariant(), 
      resourceType.ToLowerInvariant(), 
      resourceId, 
      requestDateTime.ToString("r").ToLowerInvariant(), 
      "" 
    ); 

    var hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad)); 
    var signature = Convert.ToBase64String(hashPayLoad); 

    return WebUtility.UrlEncode(string.Format(System.Globalization.CultureInfo.InvariantCulture, "type={0}&ver={1}&sig={2}", 
     keyType, 
     tokenVersion, 
     signature)); 
} 

我敢肯定,databaseid,collectionid,URL和重点是正确的。键和id是我用来查询,这是有效的。当我更改url时,例如通过添加documentid(然后生成自己),我会得到另一条消息(MethodNotAllowed)。

更新:

使用邮差,我可以看到这是响应我得到:

{ 
    "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/MyDb/colls/MyColl\nsat, 23 apr 2016 09:44:39 gmt\n\n'\r\nActivityId: 1be76530-ad32-4b54-b96b-6e0d4ebbc851" 
} 

任何提示什么,我做错了或如何分析呢?

+0

使用卷曲,使你的代码之外的请求时,它会快得多尝试不同的东西。 – Joe

+0

我使用了Postman,并将响应放入我的更新中。 – Peter

这是一个微妙的,但我用的是下面的资源ID生成散列我:

var resourceLink = string.Format("dbs/{0}/colls/{1}/docs", DatabaseId, CollectionId); 
// this becomes something like dbs/MyDb/colls/MyCollection/docs 

/docs应该被忽略。所以它变成:

var resourceLink = string.Format("dbs/{0}/colls/{1}", DatabaseId, CollectionId); 
// this becomes something like dbs/MyDb/colls/MyCollection 

但是,当我这样做时,我得到一个方法不允许的响应。这是因为我也在使用这个链接来发布帖子。但是帖子uri应该是包含/docs的链接。

所以我完整的代码现在变为:

const string DatabaseId = "DB-id"; 
const string CollectionId = "UserSettings"; 
var documentDbUrl = "Injected via DI"; 
var authorizationKey = "Also injected; 

using (var httpClient = new HttpClient()) 
{ 
    var utcNow = DateTime.UtcNow; 
    httpClient.DefaultRequestHeaders.Add("x-ms-date", utcNow.ToString("r")); 
    httpClient.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06"); 
    httpClient.DefaultRequestHeaders.Add("x-ms-documentdb-is-upsert", "true"); 

    var resourceLink = string.Format("dbs/{0}/colls/{1}", DatabaseId, CollectionId); 
    var baseUrl = new Uri(documentDbUrl); 

    var masterKeyAuthorizationSignatureGenerator = new MasterKeyAuthorizationSignatureGenerator(); 
    var authHeader = masterKeyAuthorizationSignatureGenerator.Generate("POST", resourceLink, "docs", authorizationKey, "master", "1.0", utcNow); 
    httpClient.DefaultRequestHeaders.Add("authorization", authHeader); 

    var response = await httpClient.PostAsJsonAsync(new Uri(baseUrl, resourceLink + "/docs"), userSettings); 
} 

请注意,有两种方法的URI来指定资源:

1) using the resource id. The id is user settable. 

2) using the resource _rid. This is the system generated id for the resource. 

当使用资源ID(方法1),则必须确保在级联令牌的资源ID用于散列签名令牌位于资源中使用的相同大小,因为资源ID区分大小写。例如,如果资源ID是集合的MyCollection,那么资源ID应该完全是串联标记中的MyCollection。

本文提供了构建哈希签名令牌的其他详细信息。 https://msdn.microsoft.com/en-us/library/azure/dn783368.aspx

+0

我添加了生成哈希的代码。正如你所看到的,我没有大写或压缩resourceId。 – Peter