认证令牌没有注册级别访问权限。

4

背景

我正在调用 Microsoft 的 Azure 消费端点的 restful API,如下所述。

https://learn.microsoft.com/en-gb/rest/api/consumption/reservationrecommendations/list

然而,我总是遇到以下错误。
身份验证令牌没有注册级别访问权限。
{
  "error": {
    "code": "401",
    "message": "Authentication token doesn't have enrollment level access. 
  }
}

令牌有效,可用于访问消费 API 下的其他端点。Azure 页面上的“试一试”测试链接实际上返回 200,但是当我发出调用时,却得到了 401。

问题

是否有人能够解释这个错误信息?我在任何地方都找不到关于这个错误的帮助。

代码

身份验证

https://learn.microsoft.com/en-gb/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow#first-case-access-token-request-with-a-shared-secret

 private static string GetAccessToken(string clientId, string clientSecret, string tenantId)
    {

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;");

        string hostname = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "client_credentials"),
            new KeyValuePair<string, string>("client_id", clientId),
            new KeyValuePair<string, string>("client_secret", clientSecret),
            new KeyValuePair<string, string>("resource", "https://management.azure.com/")
        });

        HttpResponseMessage httpResponse = client.PostAsync(hostname, content).Result;
        var responseString = httpResponse.Content.ReadAsStringAsync();

        if (httpResponse.StatusCode == HttpStatusCode.OK)
        {
            dynamic tokenObject = JsonConvert.DeserializeObject(responseString.Result);

            return tokenObject.access_token;
        }
        else
        {
            return null;
        }
    }

API调用

 public static dynamic GetReservationRecommendations(Params parameters)
 {
   var token = GetAccessToken(parameters.ClientId, parameters.ClientSecret, parameters.TenantId);

     HttpClient client = new HttpClient();
     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
     client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;");

     string hostname = $"https://management.azure.com/subscriptions/{parameters.SubscriptionId}/providers/Microsoft.Consumption/reservationRecommendations?api-version=2018-10-01";

     HttpResponseMessage httpResponse = client.GetAsync(hostname).Result;
     var responseString = httpResponse.Content.ReadAsStringAsync();

     if (httpResponse.StatusCode == HttpStatusCode.OK)
     {
         return responseString.Result;
     }
     else
     {
         return null;
     }
 }

它在您提到的链接中的“试一试”中能够工作吗? - Joy Wang
你能展示一下如何生成令牌的更多详细代码吗? - Joey Cai
@JoeyCai 添加了代码片段。 - Dan Cundy
2
似乎使用此令牌进行身份验证的用户没有执行此操作所需的正确权限。 - Luc
@DanCundy 我曾经看到过一些奇怪的行为,其中消耗指标仅对我们最初注册 Azure 订阅的原始用户可用,尽管他们表面上具有与其他管理员相同的权限。不过这是针对企业访问门户前端的情况,所以可能不适用,但似乎在 Azure 用户管理中存在某种额外的访问层面。 - UpQuark
显示剩余2条评论
1个回答

1

错误原因

您使用的应用程序标识在获取令牌时没有足够的权限访问“消费 API - 预订建议列表”。

测试链接有效但代码无效

据我所知,尝试测试链接将要求您首先在浏览器中使用帐户登录。因此,它使用的是用户身份而不是应用程序身份。因此,您正在进行测试的用户具有足够高的权限/角色,但是代码当然仍在使用 clientId 和 clientSecret,因此除非应用程序获得所有所需的权限,否则可能仍会失败。

所需权限

此 API 使用 ARM 权限,因此您的应用程序服务主体需要被授予权限。至少需要 "Cost Management Reader" 角色。(您可能已经完成了这些工作,因为您提到其他一些终结点对您有效) 在 Azure 门户中,转到订阅 > 您的订阅 > IAM。然后为您的应用程序的服务主体添加角色分配。查看此 Microsoft 文档以获取确切详情:分配对成本管理数据的访问权限。如果您的订阅属于 EA,请按照 EA 门户相关步骤操作。请查看此文档:在 EA 门户中启用对成本的访问。

我不确定这是否确切是问题所在,因为我已经启用了 EA 门户中的两个突出显示部分。我的应用程序服务主体也是计费阅读者,并具有访问管理 API 的权限。我正在调查授予应用程序服务主体适当特权的所有者身份,但还没有开始测试这个想法。 - Dan Cundy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接