C# 身份验证令牌不';您没有注册级别的访问权限 背景

C# 身份验证令牌不';您没有注册级别的访问权限 背景,c#,azure,jwt,azure-web-app-service,azure-management-api,C#,Azure,Jwt,Azure Web App Service,Azure Management Api,我正在对Microsoft的Azure消费端点进行restful API调用,详情如下 但是,我总是会遇到以下错误。 身份验证令牌没有注册级别的访问权限 令牌有效,可用于访问消费API下的其他端点。Azure页面上的“Try It”测试链接实际上返回了一个200,但是当我打电话时,我得到了一个401 问题 有人能解释一下这个错误消息吗?我在任何地方都找不到有关此错误的任何帮助 代码 认证 错误推理 您用于获取令牌的应用程序标识没有足够的权限使用API-保留建议列表 试一试测试链接有效,但代码

我正在对Microsoft的Azure消费端点进行restful API调用,详情如下

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

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

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

问题 有人能解释一下这个错误消息吗?我在任何地方都找不到有关此错误的任何帮助

代码 认证


错误推理

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

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

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

所需权限

  • 此API使用ARM权限,因此需要为应用程序服务主体授予权限。至少担任“成本管理读者”角色。(您可能已经这样做了,因为您提到了一些其他端点适合您)

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

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

  • 查看错误消息“身份验证令牌没有注册级别访问权限”。我认为您的Azure订阅符合EA(即企业协议)。我之所以这样说,是因为我能够在EA订阅中重新生成完全相同的错误消息,而不是在另一个常规的按量付费订阅中,当时服务负责人已经有了“成本管理阅读器”角色。如果您的订阅在EA下,那么也要遵循进一步的步骤

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

    请遵循本文档了解EA门户相关步骤


  • 它是否与您提到的链接中的
    一起使用?能否显示有关如何生成令牌的更多详细代码?@JoyWang是的。@joycai添加了代码片段。似乎使用此令牌进行身份验证的用户没有执行此操作的正确权限我不确定这到底是问题所在,因为我已经启用了EA门户中的两个突出显示的部分。我的应用程序服务负责人也是账单的读者,可以访问管理API。我正在研究给应用程序服务主体一个拥有适当特权的所有者,但还没有时间来测试这个想法。
    
    {
      "error": {
        "code": "401",
        "message": "Authentication token doesn't have enrollment level access. 
      }
    }
    
     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;
            }
        }
    
     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;
         }
     }