通过 Azure API 管理使用 DocumentDB API 的 CosmosDb

Posted

技术标签:

【中文标题】通过 Azure API 管理使用 DocumentDB API 的 CosmosDb【英文标题】:CosmosDb with DocumentDB API through Azure API Management 【发布时间】:2017-08-09 20:43:29 【问题描述】:

我正在尝试通过 API 管理查询我的新 CosmosDB 集合。一旦证明,这将是用户访问记录数据的前端。出于这个原因,我将数据按订阅 ID 进行了分区。在我的 WebApi DB 的日志集合的 Azure 门户中,我看到分区键为 /api_subscription_key。我有来自 API Mgt 的数据。 -> 事件中心 -> 流分析 -> Cosmos。

使用 Azure 门户中的查询资源管理器,我可以尝试如下查询:

SELECT * FROM c WHERE c.api_subscription_key = '573a1c65bceb52192c140131'

这带回了我已经成功写入 CosmosDB 很多天的预期文档

    [
      
        "eventenqueuedutctimesecond": "2017-07-27T15:09:02Z",
        "business_unit_key": null,
        "user_key": null,
        "api_message_id": "1718ea66-d225-45ec-b3fc-5daff4c7f426",
        "api_identifier": "21926e9d-9206-42b0-b4b1-7e7f1eb4e7dd",
        "api_id": "58d94cc622be39392343d4b6",
        "api_operation_id": "58e682bde055cd0ba4215d4b",
        "api_adapter_id": "573a1c64bceb520aac127ee5",
        "api_subscription_id": "573a1c65bceb52192c140131",
        "api_policy_id": "64BC4270-54AC-42DA-835C-E285F35BCA81",
        "basic_username": "",
        "message_version": "10",
        "claim_business_unit_key": null,
        "claim_user_key": null,
    ...
        "lasterrorsource": null,
        "lasterrorreason": null,
        "lasterrorscope": null,
        "lasterrorsection": null,
        "lasterrorpolicyid": null,
        "id": "7/27/2017 3:09:02 PM",
        "_rid": "9Fc0ANW4fwAoAAAAAAAADA==",
        "_self": "dbs/9Fc0AA==/colls/9Fc0ANW4fwA=/docs/9Fc0ANW4fwAoAAAAAAAADA==/",
        "_etag": "\"0700d90c-0000-0000-0000-597a020e0000\"",
        "_attachments": "attachments/",
        "_ts": 1501168140
      ...

我的 CosmosDB 实例是 plexconnectcosmos。通过 API 管理及其政策,我将发布到

https://plexconnectcosmos.documents.azure.com/dbs/WebApi/colls/Logs/docs

带有这些标题(许多是残留的,希望没有效果):

[

name: "Postman-Token",
value: "756c2c21-ef23-4e5a-a63a-ae6aed961d35"
,

name: "Ocp-Apim-Subscription-Key",
value: "a2a05eff128943bc89f62b81a63aa368"
,

name: "Accept-Charset",
value: "UTF-8"
,

name: "Cache-Control",
value: "no-cache"
,

name: "Content-Type",
value: "application/query+json"
,

name: "Accept",
value: "application/json;odata=nometadata"
,

name: "Accept-Encoding",
value: "gzip,deflate"
,

name: "Cookie",
value: "x-ms-gateway-slice=008; stsservicecookie=ests; BIGipServerpmc_rest_webservices_http_prod=1242575370.20480.0000"
,

name: "User-Agent",
value: "PostmanRuntime/6.2.5"
,

name: "x-ms-date",
value: "Wed, 09 Aug 2017 20:10:09 GMT"
,

name: "x-ms-version",
value: "2017-02-22"
,

name: "MaxDataServiceVersion",
value: "3.0"
,

name: "DataServiceVersion",
value: "1.0;NetFx"
,

name: "Api-Message-Id",
value: "12427ae7-7704-44cb-b4af-d7e622898b99"
,

name: "Api-Identifier",
value: "461f0c19-8df3-4272-9ac7-c64bb776dd56"
,

name: "Api-Id",
value: "58987927bceb5204c4e59168"
,

name: "Api-Operation-Id",
value: "598b3c72e055cd14fc3abdd1"
,

name: "Api-Adapter-Id",
value: "573a1c64bceb520aac127ee5"
,

name: "Api-Subscription-Id",
value: "573a1c65bceb52192c140131"
,

name: "Api-Policy-Id",
value: "64BC4270-54AC-42DA-835C-E285F35BCA81"
,

name: "X-Basic-Username",
value: ""
,

name: "x-ms-documentdb-isquery",
value: "True"
,

name: "x-ms-documentdb-query-enablecrosspartition",
value: "False"
,

name: "x-ms-max-item-count",
value: "1000"
,

name: "x-ms-documentdb-partitionkey",
value: "573a1c65bceb52192c140131"
,

name: "x-ms-partition-key",
value: "573a1c65bceb52192c140131"
,

name: "Authorization",
value: "type=master&ver=1.0&sig=Ke...Q="
,

name: "X-Forwarded-For",
value: "75.39.38.67"

]

我得到的回应是


    "code": "BadRequest",
    "message": "Partition key 573a1c65bceb52192c140131 is invalid.\r\nActivityId: 61836599-fe4b-4232-b55b-2c568eecc767"


    "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/WebApi/colls/Logs\nwed, 09 aug 2017 20:35:41 gmt\n\n'\r\nActivityId: 429....2e2"

这些似乎给了我两个需要解决的问题。首先,我该如何解决这个分区的问题?从我的分析看来,它是一个有效的分区,通过门户中的查询和标题“x-ms-documentdb-partitionkey”和“x-ms-partition-key”进行验证。 (我在 MS 文档中看到了这两个标题名称,因此我将两者都覆盖了。)

“输入的授权令牌无法处理请求。” message 在我的查询中向我暗示了一些不同的错误。我怀疑也许数据值?我的策略与我用于 Azure 表存储 REST API 的策略几乎没有什么不同,而且我从来没有遇到过这个问题。我正在使用从 Azure 门户获取并存储在 API 管理的命名值中的只读主键:

<policies>
    <inbound>
        <base />
        <set-variable name="Content-Type" value="application/query+json" />
        <set-variable name="x-ms-documentdb-isquery" value="True" />
        <set-variable name="x-ms-documentdb-query-enablecrosspartition" value="False" />
        <set-variable name="x-ms-max-item-count" value="1000" />
        <set-variable name="x-ms-version" value="2017-02-22" />
        <set-header name="Content-Type" exists-action="override">
            <value>@((string)context.Variables["Content-Type"])</value>
        </set-header>
        <set-header name="x-ms-documentdb-isquery" exists-action="override">
            <value>@((string)context.Variables["x-ms-documentdb-isquery"])</value>
        </set-header>
        <set-header name="x-ms-documentdb-query-enablecrosspartition" exists-action="override">
            <value>@((string)context.Variables["x-ms-documentdb-query-enablecrosspartition"])</value>
        </set-header>
        <set-header name="x-ms-max-item-count" exists-action="override">
            <value>@((string)context.Variables["x-ms-max-item-count"])</value>
        </set-header>
        <set-header name="x-ms-version" exists-action="override">
            <value>@((string)context.Variables["x-ms-version"])</value>
        </set-header>
        <!-- MS docs may conflict here. Possibly "x-ms-documentdb-partitionkey" req'd and "x-ms-partition-key" not supported -->
        <set-header name="x-ms-documentdb-partitionkey" exists-action="override">
            <value>@(context.Subscription.Id)</value>
        </set-header>
        <set-header name="x-ms-partition-key" exists-action="override">
            <value>@(context.Subscription.Id)</value>
        </set-header>
        <set-variable name="StringToSign" value="@(string.Format("post\ndocs\ndbs/WebApi/colls/Logs\n0\n\n", ((string)context.Variables["x-ms-date"]).ToLowerInvariant()))" />
        <set-variable name="cosmosreadonlykey" value="CosmosReadOnlyKey" />
        <set-variable name="SharedKey" value="@
        // https://docs.microsoft.com/en-us/rest/api/documentdb/access-control-on-documentdb-resources#constructkeytoken
        System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String((string)context.Variables["cosmosreadonlykey"]));
        return Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes((string)context.Variables["StringToSign"])));
" />
        <set-variable name="Authorization" value="@(string.Format("type=master&ver=1.0&sig=0", (string)context.Variables["SharedKey"]))" />
        <set-header name="Authorization" exists-action="override">
            <value>@((string)context.Variables["Authorization"])</value>
        </set-header>
        <set-backend-service base-url="https://plexconnectcosmos.documents.azure.com" />
        <rewrite-uri template="/dbs/WebApi/colls/Logs/docs" />
    </inbound>

我想知道的一些问题:返回的 ActivityId 能否帮助我获取更多详细信息,一些如何?即使没有它,在 Azure 中是否有一些我没有发现可以揭示更多细节的日志记录。

如果我在这里做的任何明显错误,请告诉我。

【问题讨论】:

【参考方案1】:

我通过一些小的调整让它运行起来。

<policies>
<inbound>
    <base />
    <set-variable name="Content-Type" value="application/query+json" />
    <set-variable name="x-ms-documentdb-isquery" value="True" />
    <set-variable name="x-ms-documentdb-query-enablecrosspartition" value="False" />
    <set-variable name="x-ms-max-item-count" value="1000" />
    <set-variable name="x-ms-version" value="2017-02-22" />
    <set-variable name="x-ms-date" value="@( DateTime.UtcNow.ToString("R") )" />
    <set-header name="Content-Type" exists-action="override">
        <value>@((string)context.Variables["Content-Type"])</value>
    </set-header>
    <set-header name="x-ms-documentdb-isquery" exists-action="override">
        <value>@((string)context.Variables["x-ms-documentdb-isquery"])</value>
    </set-header>
    <set-header name="x-ms-documentdb-query-enablecrosspartition" exists-action="override">
        <value>@((string)context.Variables["x-ms-documentdb-query-enablecrosspartition"])</value>
    </set-header>
    <set-header name="x-ms-max-item-count" exists-action="override">
        <value>@((string)context.Variables["x-ms-max-item-count"])</value>
    </set-header>
    <set-header name="x-ms-version" exists-action="override">
        <value>@((string)context.Variables["x-ms-version"])</value>
    </set-header>
    <set-header name="x-ms-documentdb-partitionkey" exists-action="override">
        <value>@("[\""+context.Subscription.Id+"\"]")</value>
    </set-header>
    <set-header name="x-ms-date" exists-action="override">
        <value>@( (string)context.Variables["x-ms-date"] )</value>
    </set-header>
    <set-variable name="StringToSign" value="@(string.Format("post\ndocs\ndbs/WebApi/colls/Logs\n0\n\n", ((string)context.Variables["x-ms-date"]).ToLowerInvariant()))" />
    <set-variable name="cosmosreadonlykey" value="CosmosReadOnlyKey" />
    <set-variable name="SharedKey" value="@
    // https://docs.microsoft.com/en-us/rest/api/documentdb/access-control-on-documentdb-resources#constructkeytoken
    System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String((string)context.Variables["cosmosreadonlykey"]));
    return Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes((string)context.Variables["StringToSign"])));
" />
    <set-variable name="Authorization" value="@(string.Format("type=master&ver=1.0&sig=0", ((string)context.Variables["SharedKey"]).Replace("&","%26").Replace("+","%2B").Replace("=","%3D")))" />
    <set-header name="Authorization" exists-action="override">
        <value>@((string)context.Variables["Authorization"])</value>
    </set-header>
    <set-backend-service base-url="https://mycosmosdb.documents.azure.com" />
    <rewrite-uri template="/dbs/WebApi/colls/Logs/docs" />
</inbound>
</policies>
    the partition key needs to be formatted as an array 日期放入header和StringToSign基于相同的值 did some hacky URL hex encoding - 可以通过适当的十六进制编码进行改进

【讨论】:

这太棒了。让我看看我们可以做些什么来让编码变得更容易。 谢谢,@KaiWalter 格式化为数组的分区键真正让我着迷。 @DarrelMiller APIM 团队有没有考虑过更好的编码选项?我们有一个带有加号的秘密。希望在政策中看到本机编码功能 @Josh 遗憾的是,我不知道最近在这方面有什么工作。

以上是关于通过 Azure API 管理使用 DocumentDB API 的 CosmosDb的主要内容,如果未能解决你的问题,请参考以下文章

正文未通过 Azure API 管理发送

通过 Azure API 管理生成访问令牌并针对 IdentityServer4 进行验证

我们可以在不使用 SAS 令牌的情况下通过 c# 代码调用 Azure API 管理吗

有没有办法通过 Azure API 管理中的订阅来改变速率限制的值

通过 APIM 使用 Azure 功能的 REST URL

通过 JWT 令牌在 Azure API 管理中进行授权