身份验证令牌没有注册级别访问权限

时间:2018-11-29 11:06:55

标签: c# azure jwt azure-web-app-service azure-management-api

背景

我正在对Microsoft的Azure消费终结点进行一次宁静的API调用,如下所述。

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

但是,我总是遇到以下错误。

  

身份验证令牌没有注册级别访问权限。

{
  "error": {
    "code": "401",
    "message": "Authentication token doesn't have enrollment level access. 
  }
}

令牌有效,可用于访问消费API下的其他端点。 Azure页面上的“ Try It”测试链接实际上返回200,但是当我拨打电话时得到401。

问题

任何人都可以阐明此错误消息吗?我在任何地方都找不到有关此错误的任何帮助。

代码

身份验证

https://docs.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;
     }
 }

1 个答案:

答案 0 :(得分:1)

错误原因

您用于获取令牌的应用程序标识没有足够的权限使用Consumption API-预留建议列表

尝试测试链接有效,但代码无效

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

所需权限

  1. 此API使用ARM权限,因此需要为您的应用程序服务主体提供权限。至少具有“成本管理阅读器”角色。 (由于提到了其他一些端点,因此您可能已经做了这些工作)

    在Azure门户中,转到“订阅”>“您的订阅”>“ IAM”

    enter image description here

    然后为应用程序的服务主体添加角色分配

    enter image description here

  2. 在查看错误消息“身份验证令牌没有注册级别访问权限。”,我认为您的Azure订阅位于EA(即企业协议)下。我之所以这样说是因为,当服务主体已经具有“成本管理读取器”角色时,我只能在EA订阅中复制完全相同的错误消息,而在另一个常规的即用即付订阅中则无法复制。如果您的订阅是在EA下,则也请按照以下步骤操作。

    因此,需要在Azure门户和企业门户(EA门户)中授予权限。有关详细信息,请参阅此Microsoft文档。 Assign access to Cost Management data

    enter image description here

    enter image description here

    请遵循此文档以了解与EA门户相关的步骤。 Enable access to costs in the EA portal enter image description here