【问题标题】:Unauthorized status while accessing Cosmos Db Collection Documents in power shell在 power shell 中访问 Cosmos Db 集合文档时处于未授权状态
【发布时间】:2020-07-28 06:09:09
【问题描述】:

我正在尝试访问 azure cosmos db 帐户集合文档以及集合中的每个文档。我参考了下面的链接并更改了所有必要的 cosmos db 值,例如 databaseid、container、itemid 主密钥等,

链接:

https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/PowerShellRestApi/PowerShellScripts/ReadItem.ps1

但我在 Powershell 中运行时遇到错误。

错误:

  StatusCode: 401
  Exception Message: The remote server returned an error: (401) Unauthorized.
  System.Net.WebException: The remote server returned an error: (401) Unauthorized.
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
  at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()

注意:当我在邮递员中尝试相同时,我正在获取文档列表,但是当我尝试获取特定文档时。我遇到了错误。

错误:

  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:

仅供参考:我是 azure 门户中 Cosmodb 帐户的贡献者角色

参数:

   $endpoint = "https://testcosmos.documents.azure.com:443/"
  $MasterKey = "<Key from Cosmos db account>"
  $KeyType = "master"
 $TokenVersion = "1.0"
 $date = Get-Date
 $utcDate = $date.ToUniversalTime()
 $xDate = $utcDate.ToString('r', 
  [System.Globalization.CultureInfo]::InvariantCulture)
 $databaseId = "testdb"
  $containerId = "containercollection"
 $itemResourceType = "docs"
$ItemId="1"
 $itemResourceId = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"
  $itemResourceLink = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"
  $verbMethod = "GET"

  $header = @{

    "authorization"         = "$authKey";

    "x-ms-version"          = "2018-12-31";

   "Cache-Control"         = "no-cache";

    "x-ms-date"             = "$xDate"

    "Accept"                = "application/json";

    "User-Agent"            = "PowerShell-RestApi-Samples";

    "x-ms-documentdb-partitionkey" = '["testPK"]'
}

我曾尝试评论“Accept”、“User-Agent”、Cache-Control 标头选项,但没有成功。 我也尝试只获取没有 itemID 的 /docs 列表,但这也是徒劳的。

$result = Invoke-RestMethod -Uri $requestUri -Headers $header -Method $verbMethod -ContentType "application/json"
Write-Host "Read item response = "$result

更新代码:我终于明白为什么会出现问题了。它既不是身份验证问题也不是资源ID。我在标题中传递分区键,这些分区键不是按照 sample 硬编码的。当我将值传递给分区键时,它没有正确使用,因此导致问题。下面是我的动态代码传递分区键

"x-ms-documentdb-partitionkey" = '["$Partitionkey"]' -- Displaying as 
[$Partitionkey] but it must print in headers like ["partitionkeyValue"]

正在尝试如何解决这个问题。非常感谢您的建议。

【问题讨论】:

  • 请编辑您的问题并包含您传递给此 PS 函数的参数。
  • 您的$itemResourceId$itemResourceLink 中不是缺少$ItemId 吗?他们都应该是"dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"+$ItemId
  • 添加 $itemId 也会产生同样的错误。所以我特意删除了我是否得到了整个文档列表但没有得到
  • 我刚刚从github.com/Azure/azure-cosmos-dotnet-v3/blob/master/…(您引用的链接)复制了代码并运行了代码,我能够获取文档详细信息。我只是根据我的帐户设置更改了端点、主密钥、数据库和容器 ID。
  • 团队,我更新了我的代码

标签: powershell azure-cosmosdb azure-powershell azure-cosmosdb-sqlapi


【解决方案1】:

首先,我可以使用与@Gaurav Mantri 相同的github 代码成功查询我的项目。您的错误代码是401 auth issue,所以我假设您在生成MasterKeyAuthorizationSignature 时犯了一些错误,尤其是$itemResourceId 的值。请参考REST API document

2 部分:

1.查询特定项目:

$itemId = "1"
$itemResourceType = "docs"
$itemResourceId = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"+$ItemId
$itemResourceLink = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"+$ItemId

2.列出特定集合中的项目:

没有#itemId

$itemResourceId = "dbs/"+$databaseId+"/colls/"+$containerId
$itemResourceLink = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"

【讨论】:

    【解决方案2】:

    我尝试了以下代码,它对我来说效果很好。我能够获取文档详细信息:

    Add-Type -AssemblyName System.Web
    
    Function Generate-MasterKeyAuthorizationSignature{
    
        [CmdletBinding()]
    
        param (
    
            [string] $Verb,
            [string] $ResourceId,
            [string] $ResourceType,
            [string] $Date,
            [string] $MasterKey,
            [String] $KeyType,
            [String] $TokenVersion
        )
    
        $keyBytes = [System.Convert]::FromBase64String($MasterKey)
    
        $sigCleartext = @($Verb.ToLower() + "`n" + $ResourceType.ToLower() + "`n" + $ResourceId + "`n" + $Date.ToString().ToLower() + "`n" + "" + "`n")
        Write-Host "sigCleartext = " $sigCleartext
    
        $bytesSigClear = [Text.Encoding]::UTF8.GetBytes($sigCleartext)
    
        $hmacsha = new-object -TypeName System.Security.Cryptography.HMACSHA256 -ArgumentList (, $keyBytes)
    
        $hash = $hmacsha.ComputeHash($bytesSigClear) 
    
        $signature = [System.Convert]::ToBase64String($hash)
    
        $key = [System.Web.HttpUtility]::UrlEncode('type='+$KeyType+'&ver='+$TokenVersion+'&sig=' + $signature)
    
        return $key
    }
    
    $endpoint = "https://account-name.documents.azure.com:443/"
    $MasterKey = "account-key"
    
    $KeyType = "master"
    $TokenVersion = "1.0"
    $date = Get-Date
    $utcDate = $date.ToUniversalTime()
    $xDate = $utcDate.ToString('r', [System.Globalization.CultureInfo]::InvariantCulture)
    $databaseId = "MyDatabaseId"
    $containerId = "MyContainerId"
    $itemId = "TestItem"
    $itemResourceType = "docs"
    $itemResourceId = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"+$ItemId
    $itemResourceLink = "dbs/"+$databaseId+"/colls/"+$containerId+"/docs/"+$ItemId
    $verbMethod = "GET"
    
    $requestUri = "$endpoint$itemResourceLink"
    
    $authKey = Generate-MasterKeyAuthorizationSignature -Verb $verbMethod -ResourceId $itemResourceId -ResourceType $itemResourceType -Date $xDate -MasterKey $MasterKey -KeyType $KeyType -TokenVersion $TokenVersion
    
    $header = @{
    
            "authorization"         = "$authKey";
    
            "x-ms-version"          = "2018-12-31";
    
            "Cache-Control"         = "no-cache";
    
            "x-ms-date"             = "$xDate";
    
            "Accept"                = "application/json";
    
            "User-Agent"            = "PowerShell-RestApi-Samples";
    
            "x-ms-documentdb-partitionkey" = '["testPk"]'
        }
    
    try {
        $result = Invoke-RestMethod -Uri $requestUri -Headers $header -Method $verbMethod -ContentType "application/json"
        Write-Host "Read item response = "$result
        return "ReadItemSuccess";
    }
    catch {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "Exception Message:" $_.Exception.Message
        echo $_.Exception|format-list -force
    }
    

    更新

    关于您关于动态指定分区键值的评论,请尝试以下操作:

    "x-ms-documentdb-partitionkey" = '["' + $Partitionkey + '"]'
    

    【讨论】:

    • 嗨,当我尝试上述测试时,我有一个问题。如果我在没有分区键字段的分区集合中有一个项目(假设 pk 是name)。因为这个项目没有name 列。然后如何设置"x-ms-documentdb-partitionkey",我可以在java sdk中设置Undefined.Value(),效果很好。但是这里的PS没有运气。我试过""{}。如果您有任何想法,请您指导我吗?提前谢谢你。
    • @JayGong 好问题!我试过{},它对我有用。这是我使用的:"x-ms-documentdb-partitionkey" = '[{}]'.
    • 如果我每次调用 API 时都必须传递一些动态值怎么办。假设我有分区键,我想每次传递一个不同的值而不是硬编码。我尝试如下“x-ms-documentdb-partitionkey”=“[”+$Partitionkey+“]” - 打印 [TESTPK] 而不是 [“TESTPK”]
    • 试试"x-ms-documentdb-partitionkey" = '["' + $Partitionkey + '"]'。它应该可以工作。
    • 工作感谢。
    猜你喜欢
    • 1970-01-01
    • 2018-01-13
    • 2019-09-19
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多