使用 bash、Azure CLI 和 REST API 访问 CosmosDB - 如何正确获取令牌和哈希?

2024-04-18

我的最终目标是使用 bash 和 Azure CLI 将文档上传到现有的 CosmosDB (SQL) 实例。问题是:Azure CLI 确实如此不提供修改文档的命令 https://learn.microsoft.com/en-us/cli/azure/cosmosdb?view=azure-cli-latest.

为了解决这个问题,我研究了az rest命令并希望调用 CosmosDB 的 REST API 来完成任务,但经过几个小时的不成功尝试后,我总是收到错误:

Unauthorized({"code":"未授权","message":"输入授权 令牌无法满足请求。请检查预期的有效负载 根据协议构建,并检查正在使用的密钥。服务器 使用以下有效负载进行签名:'get\ndbs\n\nsat, 25 apr 2020 13:50:22 +0000\n\n'\r\n活动 ID: ..., Microsoft.Azure.Documents.Common/2.10.0"})

为了现在简单起见,我尝试使用 REST API 列出我的所有数据库,如文档中所述 https://learn.microsoft.com/en-us/rest/api/cosmos-db/list-databases如果可行,请继续实际的文档上传。

我也尝试按照提供的说明进行操作在文档中 https://learn.microsoft.com/rest/api/cosmos-db/access-control-on-cosmosdb-resources关于如何生成授权标头。

获取数据库列表的请求使用以下格式:GET https://{databaseaccount}.documents.azure.com/dbs

这是我的 bash 脚本,其中突出显示了问题。

第 1 部分:获取访问令牌 -question:这是正确的开始吗?

masterKey=$(az cosmosdb keys list --name MYDBINSTANCENAME --query primaryMasterKey --output tsv)

第 2 部分:生成要哈希的有效负载 - 所有内容必须为小写

verb="get"
resourceType="dbs"
resourceLink="dbs"
now=$((date -uR) | tr '[A-Z]' '[a-z]')
payload="$verb\n$resourceType\n$resourceLink\n$now\n\\n"

第 3 部分:对有效负载进行哈希处理 -issue:这个哈希的结果不同于C# 中的示例代码构建了什么 https://learn.microsoft.com/rest/api/cosmos-db/access-control-on-cosmosdb-resources#constructkeytoken。因此,其中之一必定是错误的,但两者都会导致相同的错误消息。

hashedPayload=$(printf $payload | openssl dgst -sha256 -hmac $masterKey -binary)

第 4 部分:创建所需的身份验证字符串并转换为 Base 64 -问题:是使用时所需的 Base 64 编码az rest?

authString="type=master&ver=1.0&sig=$hashedPayload" | base64

第 5 部分:创建标头字符串。这是使用 JSON 表示法,因为空白分隔方法不起作用,尽管文档声明它应该 https://learn.microsoft.com/cli/azure/reference-index?view=azure-cli-latest#az-rest-required-parameters.

headers="{\"x-ms-date\": \"$now\", \"x-ms-version\": \"2018-12-31\", \"x-ms-documentdb-isquery\": \"true\", \"Content-Type\": \"application/query+json\", \"Authorization\": \"$authString\"}"

第 6 部分:调用 REST API

az rest --verbose -m get -u "https://MYDBINSTANCENAME.documents.azure.com:443/dbs" --headers $headers

Output:

Request URL: 'https://MYDBINSTANCENAME.documents.azure.com:443/dbs'
Request method: 'GET'
Request headers:
    'User-Agent': 'AZURECLI/2.4.0 (HOMEBREW)'
    'Accept-Encoding': 'gzip, deflate'
    'Accept': '*/*'
    'Connection': 'keep-alive'
    'x-ms-date': 'sat, 25 apr 2020 13:54:10 +0000'
    'x-ms-version': '2018-12-31'
    'x-ms-documentdb-isquery': 'true'
    'Content-Type': 'application/query+json'
    'Authorization': 'type%3dmaster%26ver%...'
    'x-ms-client-request-id': 'a55357fe-411c-4adf-9fd6-1a255e010cca'
    'CommandName': 'rest'
    'ParameterSetName': '--verbose -m -u --headers'
Request body:
None
Response status: 401
Response headers:
    'Transfer-Encoding': 'chunked'
    'Content-Type': 'application/json'
    'Content-Location': 'https://MYDBINSTANCENAME.documents.azure.com/dbs'
    'Server': 'Microsoft-HTTPAPI/2.0'
    'x-ms-activity-id': '9119f8bd-53d9-4a87-8aff-a887ec652fed'
    'Strict-Transport-Security': 'max-age=31536000'
    'x-ms-gatewayversion': 'version=2.10.0'
    'Date': 'Sat, 25 Apr 2020 13:54:11 GMT'
Response content:
{"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: 'get\ndbs\n\nsat, 25 apr 2020 13:54:10 +0000\n\n'\r\nActivityId: 9119f8bd-53d9-4a87-8aff-a887ec652fed, Microsoft.Azure.Documents.Common/2.10.0"}

感谢您的支持@Gaurav Mantri 和@Mark Brown。您的评论有助于避免一百万次被纸割伤而死亡:-)

我启动了一个存储库,在其中收集 Azure CLI bash 脚本。找到它在https://github.com/Krumelur/AzureScripts https://github.com/Krumelur/AzureScripts

让我回答我自己的问题并提供一个读取 CosmosDB 实例中现有数据库的脚本。

这将在浏览器窗口中启动交互式登录。

az login

指定我们要访问的资源。 URI 以及所需的参数值可以在以下位置找到:https://learn.microsoft.com/en-us/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest https://learn.microsoft.com/en-us/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest

comsosDbInstanceName="YOUR INSTANCE NAME GOES HERE"
baseUrl="https://$comsosDbInstanceName.documents.azure.com/"
verb="get"
resourceType="dbs"
resourceLink="dbs"
resourceId=""

获取 CosmosDB 的主密钥。我们需要这个才能访问。该密钥与门户上 CosmosDB 实例的“密钥”部分中找到的密钥相同。主键是 REST API 所说的“主”键。

masterKey=$(az cosmosdb keys list --name $comsosDbInstanceName --query primaryMasterKey --output tsv)
echo "Masterkey: $masterKey"

CosmosDB REST API 需要哈希授权标头:https://learn.microsoft.com/de-de/rest/api/cosmos-db/access-control-on-cosmosdb-resources#authorization-header https://learn.microsoft.com/de-de/rest/api/cosmos-db/access-control-on-cosmosdb-resources#authorization-header

要获取 HTTP 格式的日期,区域设置必须设置为 US。否则,日期名称将被本地化(例如德语)。

bash 不直接支持 HTTP 格式。要使其正常工作,请将当前时区设置为 GMT。时间格式如下所示:“mon, 27 apr 2020 09:46:58 gmt”。

now=$(env LANG=en_US TZ=GMT date '+%a, %d %b %Y %T %Z')
echo "Date: " $now

以预期格式连接动词、资源类型、资源 ID 和日期。 REST API 要求签名为小写。

我没有意识到的“小”问题:尾随换行符(\n) 在输出字符串时总是被截断。这会破坏哈希值,因为 CosmosDB 期望它们在那里。这就是为什么在小写操作之后添加了两个尾随换行符。

signature="$(printf "%s" "$verb\n$resourceType\n$resourceId\n$now" | tr '[A-Z]' '[a-z]')\n\n"
echo "Signature: $signature"

使用 CosmosDB 实例的主键计算签名的哈希值。 看https://superuser.com/questions/1546027/what-is-the-openssl-equivalent-of-this-given-c-hashing-code/1546036 https://superuser.com/questions/1546027/what-is-the-openssl-equivalent-of-this-given-c-hashing-code/1546036了解为什么这如此棘手的详细信息。 tl;博士;版本:OpenSSL 和服务器实现对散列密钥的解释不同。

hexKey=$(printf "$masterKey" | base64 --decode | hexdump -v -e '/1 "%02x"')
echo "Hex key: " $hexKey
hashedSignature=$(printf "$signature" | openssl dgst -sha256 -mac hmac -macopt hexkey:$hexKey -binary | base64)
echo "Hashed signature: $hashedSignature"```

哈希签名预计会进行 URL 编码。当然,bash 中没有内置方法可以做到这一点。天啊。 幸运的是,我们正在处理一个 Base64 字符串。唯一需要编码的字符是等号,它变成“%3d”。

使用格式“type={typeoftoken}&ver={tokenversion}&sig={hashsignature}”构建授权标头

authString="type=master&ver=1.0&sig=$hashedSignature"
echo "Auth string: $authString"

Auth 字符串应采用 URL 编码。当然,bash 中没有内置方法可以做到这一点。天啊。 这不是完整的 Base64 编码,而是仅更改我们可能看到的字符: = -> %3d, & -> %26, + => %2b, / => %2f

urlEncodedAuthString=$(printf "$authString" | sed 's/=/%3d/g' | sed 's/&/%26/g' | sed 's/+/%2b/g' | sed 's/\//%2f/g')
echo "URL encoded auth string: $urlEncodedAuthString"

通过组合基本 URL 和资源链接进行 API 调用。

url="$baseUrl$resourceLink"
echo "URL: $url"

可以使用“azrest”命令:

az rest --verbose -m $verb -u $url --headers x-ms-date="$now" x-ms-version=2018-12-31 x-ms-documentdb-isquery=true Content-Type=application/query+json Authorization=$urlEncodedAuthString --debug

替代方案:使用 cURL

curl --request $verb -H "x-ms-date: $now" -H "x-ms-version: 2018-12-31" -H "x-ms-documentdb-isquery: true" -H "Content-Type: application/query+json" -H "Authorization: $urlEncodedAuthString" $url
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 bash、Azure CLI 和 REST API 访问 CosmosDB - 如何正确获取令牌和哈希? 的相关文章

随机推荐

  • 一个本地 .resx 字符串可以引用另一个本地 .resx 字符串吗?

    我正在尝试确定是否可以将串联字符串添加到我的本地 resx 文件之一 这个例子应该澄清 假设我有一个简单的 ASP NET 网页 由 1 一个标签 其文本是重要关键字 2 一个带有必填字段验证的输入和 3 一个导致验证发生的按钮组成 lbl
  • JodaTime中如何获取本机的时区?

    如何检测本地计算机所在的时区 I tried DateTimeZone getDefault 但如果机器位于德国 那么这不会给我例如时区 德国 有可能吗 DateTimeZone getDefault 如果您的主机位于德国 将返回您的时区
  • 没有 jpa 的 Spring 和 Hibernate

    对于我的新项目 我计划使用 Hibernate 5 和 Spring 4 并且一如既往地喜欢分成不同的层 项目 梯度依赖 org springframework spring webmvc 4 2 1 RELEASE org springf
  • 获取.NET程序集的日期[重复]

    这个问题在这里已经有答案了 如何从当前 NET 程序集中检索创建日期 我想添加一些非常简单的功能 让我的应用程序在主程序集构建日期一周后停止工作 我已经编写了在给定日期后杀死我的应用程序的代码 我只需要以编程方式从程序集中检索创建日期 以下
  • 分析 mex 函数

    我刚刚用 c 将 Matlab 程序重写为 mex 函数以加快速度 并取得了出色的结果 这个优化决策是一个非常非常好的主意 无需线程即可将速度提高 20 倍 它仍然让我很好奇 mex 函数将时间花在什么上 并希望找出可能的瓶颈 我正在寻找一
  • 创建自定义表格表示的函数

    我使用下面的代码来概述我的部分数据 从以下代码中创建函数的最佳方法是什么 它将采用 dataList 以及一些图形选项 例如颜色 作为参数 并返回自定义的表格表示形式 如下所示 overviewtheData Text Grid Map R
  • Symfony 2 FOS 用户捆绑包 Bootstrap 模式 AJAX 登录

    有没有人已经使用 Symfony 2 和 FOS User Bundle 在 Bootstrap 模式中构建了登录表单 这是我现在所拥有的 src Webibli UserBundle Resources config service ym
  • 使用 PHP 生成 Windows .lnk 文件

    我正在开发一个项目 其中涉及运行 ProFTPd 的 FTP 服务器和为用户创建帐户的 PHP MySQL 后端 创建帐户后 系统会向用户发送电子邮件 其中包含其帐户详细信息以及下载 FileZilla 或 Cyber Duck 的说明 具
  • Publish 不是改造 web.config 吗?

    我制造了一个web config 完整文件 http pastebin com rYreaVyP 它不显示 XML 错误
  • 如何从 HttpInputStream 获取 docx 文件的字节数组?

    我正在使用这篇文章第一个答案中的方法 如何从 HttpPostedFile 创建字节数组 https stackoverflow com questions 359894 how to create byte array from http
  • 如何写入 stdIn (JAVA) [重复]

    这个问题在这里已经有答案了 我想通过使用一些输入 例如 join 8 对我的 P2P 系统进行一些测试 8 是节点号 对于我的系统 命令 join 8 是从标准输入读取的 但我不想将其键入数百次以进行数百次测试 因此我编写了一个测试函数来随
  • HTML5 视频 - 在特定时间开始视频并播放 x 时间

    我正在尝试创建在特定时间点启动本地视频并播放特定持续时间的按钮 我已经让它在某个时刻播放 但不知道如何让它只播放一定的持续时间 这是代码 HTML
  • C++ 中的叉积

    给定以下Python 来自http norvig com sudoku html http norvig com sudoku html def cross A B Cross product of elements in A and el
  • 使用 Terraform(工作区、模块?)配置客户帐户最佳实践?

    我需要在 AWS 中创建和管理多个客户环境 并且希望利用 Terraform 来部署所有必要的资源 每个客户环境基本相同 只是用于访问其中一台服务器的 URL 不同 我已经整理了一个 Terraform 配置 可以为给定客户部署所有资源 但
  • 来自本地运行的 docker 容器内的 Azure 托管身份

    我正在运行一个由 asp net core 2 2 api 组成的 docker 容器 此 api 需要访问 Azure 密钥保管库 并且我已使用在密钥保管库上具有正确访问策略的用户登录 Visual Studio 以检索机密 但是 当我使
  • 为什么 JDBC 是动态加载而不是导入? [复制]

    这个问题在这里已经有答案了 在 JDBC 中 我只看到使用的示例 Class forName com mysql jdbc Driver true cl 还没有看到有人使用 import com mysql jdbc Driver 是不是因
  • 从 MySQL 数据库中选择随机问题; “正确答案”搞砸了

    我正在使用 PHP 和 MYSQL 构建一个简单的测验程序 测验旨在一次显示一个问题 问题为多项选择题 每个问题有 4 个可能的答案 如果玩家选择正确 他将进入下一个问题 如果他选错了 测验就会结束 首先 我设计的测验如下 1 创建一个数据
  • 如何使用 Spring 表达式语言将不带构造函数的对象添加到列表中

    我想添加一个BigDecimal使用 Spring 表达式语言的列表 public class SpelTest public List
  • 检查 iterable 的所有值是否为零

    有没有一种好的 简洁 内置的方法来查看可迭代中的所有值是否为零 现在我正在使用all 有一点列表理解 但是 对我来说 似乎应该有一种更具表现力的方法 我认为这在某种程度上相当于memcmp in C values 0 0 0 0 0 Tes
  • 使用 bash、Azure CLI 和 REST API 访问 CosmosDB - 如何正确获取令牌和哈希?

    我的最终目标是使用 bash 和 Azure CLI 将文档上传到现有的 CosmosDB SQL 实例 问题是 Azure CLI 确实如此不提供修改文档的命令 https learn microsoft com en us cli az