【问题标题】:Why do I get a 401 using a Shared Access Signature with the Service Bus REST API为什么使用服务总线 REST API 的共享访问签名会得到 401
【发布时间】:2021-12-09 02:39:06
【问题描述】:

我正在尝试验证我是否可以使用 Azure 共享访问策略主键手动滚动 SAS 并发布到服务总线主题。但我总是得到一个 401。四处搜索,下面的代码看起来是正确且常见的地方来实现这一点。我错过了一些基本的东西吗?我是否使用了错误的密钥(即来自门户管理员的共享访问策略主密钥)? (注意我故意使用 RootManageSharedAccessKey 来测试)

            var baseUrl = "https://<< NAMESPACE >>.servicebus.windows.net/";
            var key = "<< SHARED ACCESS KEY >>";

            TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
            var week = 60 * 60 * 24 * 7;
            var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
            string stringToSign = HttpUtility.UrlEncode(baseUrl) + "\n" + expiry;
            HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
            var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(baseUrl), HttpUtility.UrlEncode(signature), expiry, "RootManageSharedAccessKey");
            var msg = new HttpRequestMessage()
            {
                RequestUri = new Uri(baseUrl + "things"),
                Method = HttpMethod.Post
            };
            msg.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
            msg.Headers.Add("Authorization", $"SharedAccessSignature sr={HttpUtility.UrlEncode(baseUrl)}&sig={sasToken}&se={expiry}&skn=things");
            var client = new HttpClient();
            var r = client.Send(msg);
            Console.WriteLine(r.StatusCode);

【问题讨论】:

  • 请尝试将您的 baseUrl 更改为 https://&lt;&lt; NAMESPACE &gt;&gt;.servicebus.windows.net/things
  • 谢谢,我试过了,但许多示例显示了一个基本 URL,它排除了主题名称或指定队列名称的“消息”部分。在 url 中包含“things”仍然会返回未经授权的
  • 根共享访问密钥有权访问整个命名空间,包括任何子实体 - 所以命名空间级别的 URI 应该没问题。
  • 您是否有机会添加一个示例,说明您的标题看起来像实际 SAS 编辑的样子?

标签: c# azure rest azureservicebus shared-access-signatures


【解决方案1】:

我强烈怀疑您看到失败是因为您的 baseUrl 中的尾部斜杠。该表单应为:&lt;&lt; NAMESPACE &gt;&gt;.servicebus.windows.net,我不认为在服务验证时它会被视为规范化 URL - 因此斜杠是有意义的。 (ref)

您的签名格式看起来是正确的,并且似乎使用了docs 中的 sn-p 几乎一字不差。对于您的实际应用程序使用,我建议您处理 HMACSHA256 实例并确保您将 HttpClient 视为单例。

如果有帮助,可以找到服务总线 SDK 如何形成 SAS 的来源here

【讨论】:

  • 对实际源代码的好调用!完全忘了我可以查一下。我可以看到我正在正确地创建签名,即使我复制了构建签名的源代码,我仍然会得到 401,所以一定是在做一些根本上错误的事情。即使删除了反斜杠。我得到的实际令牌是不同的 - 我会看看 - 但如果 BuildSignature 创建的标头不起作用....
  • 我之前专注于签名生成,但看看标题的形成,你有skn=thing - 这是你的主题。该参数正在寻找共享密钥的名称。此外,请务必仔细检查您的请求 URI。斜线消失后,如果您没有调整 URL 的形成方式,它将是错误的。
  • HTTP 401 通常表示“我们不知道您是谁”,而不是“我们知道您是谁,但您无权执行此操作”。这让我觉得我们的标题仍然存在问题。 (尽管较旧的 Azure API 在遵循 REST 约定方面并不出色……)一个示例可能会有所帮助。
  • 很高兴你至少离得更近了;我忘记了 Service Bus SDK 还通过 HTTP 与旧的 ATOM API 对话——它的行为应该与您正在使用的端点类似。形成这些请求的代码可以在here 找到,以防您想参考。
  • 最终更新 - 哇,最后总是很愚蠢,尽管这不是最初的问题。当我将 HTTP 编码更改为使用 WebUtility 而不是 HttpUtility 时,在我自己的 sig 创建中,我对字符串进行了编码以使用 WebUtility 进行签名,但将请求 URL(sr 参数)的编码留给了 HttpUtility。因此存在不匹配,例如编码上的 %a 与 %A ......在取消散列后进行比较时,预计会转换为常见情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
  • 2020-01-02
相关资源
最近更新 更多