通过 APIM 频繁调用 CosmosDB API 时
send-request
有时我会收到 401 Unauthorized,有时会收到我期望的 200。我尝试生成相同的请求并使用 Postman 频繁发送它,并且响应始终为 200。
这是 APIM 策略代码片段:
<set-variable name="currentDate" value="@(DateTime.UtcNow.ToString("r"))" />
<set-variable name="userMetadataCosmosDBKey" value="{{UserMetadataCosmosDBKey}}" />
<set-variable name="userMetadataCosmosDBUri" value="{{UserMetadataCosmosDBUri}}" />
<set-variable name="userMetadataResourceId" value="{{UserMetadataResourceId}}" />
<set-variable name="token" value="@{
var verb = "POST";
var resourceType = "docs";
var resourceId = (string)context.Variables["userMetadataResourceId"];
var date = (string)context.Variables["currentDate"];
var key = (string)context.Variables["userMetadataCosmosDBKey"];
var keyType = "master";
var tokenVersion = "1.0";
var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
verb = verb ?? "";
resourceType = resourceType ?? "";
resourceId = resourceId ?? "";
string payLoad = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n",
verb.ToLowerInvariant(),
resourceType.ToLowerInvariant(),
resourceId,
date.ToLowerInvariant(),
"");
byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
string signature = Convert.ToBase64String(hashPayLoad);
return String.Format("type={0}&ver={1}&sig={2}",
keyType,
tokenVersion,
signature);
}" />
<send-request mode="new" response-variable-name="userMetadataResponse" timeout="20" ignore-error="false">
<set-url>@(new Uri(string.Format("{0}{1}/docs",(string)context.Variables["userMetadataCosmosDBUri"],(string)context.Variables["userMetadataResourceId"])).ToString())</set-url>
<set-method>POST</set-method>
<set-header name="x-ms-documentdb-isquery" exists-action="override">
<value>true</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/query+json</value>
</set-header>
<set-header name="x-ms-version" exists-action="override">
<value>2017-02-22</value>
</set-header>
<set-header name="x-ms-date" exists-action="override">
<value>@((string)context.Variables["currentDate"])</value>
</set-header>
<set-header name="x-ms-query-enable-crosspartition" exists-action="override">
<value>true</value>
</set-header>
<set-header name="Authorization" exists-action="override">
<value>@((string)context.Variables["token"])</value>
</set-header>
<set-body>@{
return new JObject(
new JProperty("query","SELECT * FROM c WHERE c.APIMUserId=@apiUserId"),
new JProperty("parameters",
new JArray(
new JObject(
new JProperty("name","@apiUserId"),
new JProperty("value", context.User.Id)
)
)
)
).ToString();
}</set-body>
</send-request>
<!-- Store response body in userMetadata variable -->
<set-variable name="userMetadata" value="
@{
var response = ((IResponse)context.Variables["userMetadataResponse"]).Body.As<JObject>(true);
var metadata = response["_count"].ToString() == "1" ? response["Documents"][0] : new JObject();
return metadata;
}" />
有想过为什么我有时会收到 401 吗?
通过将
System.Uri.EscapeDataString()
添加到返回的令牌来使其工作:
System.Uri.EscapeDataString(String.Format("type={0}&ver={1}&sig={2}",
keyType,
tokenVersion,
signature));
您也可以使用
<authentication-managed-identity
resource="https://cosmon-samples-234f1f22a3.documents.azure.com"
output-token-variable-name="msi-access-token"
ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>@("type=aad&ver=1.0&sig=" + context.Variables["msi-access-token"])</value>
</set-header>
验证对 CosmosDB 的 APIM 请求。 只需确保您已在 CosmosDB RBAC 中授予权限 https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-setup-rbac
包含所有详细信息的完整示例可以在我的文章中找到https://byalexblog.net/article/azure-apimanagement-to-azure-cosmosdb/