通过 Azure APIM 发送请求调用 Cosmos DB Api 时出现 401 Unauthorized
401 Unauthorized when calling Cosmos DB Api via Azure APIM send-request
当通过 APIM send-request
频繁调用 CosmosDB API 时,有时我会收到 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));
当通过 APIM send-request
频繁调用 CosmosDB API 时,有时我会收到 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));