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

Posted

技术标签:

【中文标题】身份验证令牌没有注册级别访问权限【英文标题】:Authentication token doesn't have enrollment level access 【发布时间】:2019-05-01 10:24:15 【问题描述】:

背景

我正在对 Microsoft 的 Azure 消费端点进行 RESTful 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;
     
 

【问题讨论】:

您提到的链接中的Try it 是否有效? 能否提供更多关于如何生成令牌的详细代码? @JoyWang 是的。 @JoeyCai 添加了代码 sn-p。 似乎使用此令牌进行身份验证的用户没有执行此操作的正确权限 【参考方案1】:

错误原因

您用于获取令牌的应用程序身份没有足够的权限消费API - 预订推荐列表

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

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

所需权限

    此 API 使用 ARM 权限,因此您的应用程序服务主体需要获得权限。至少有“成本管理读者”的角色。 (您可能已经完成了这些,因为您提到了其他一些对您有用的端点)

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

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

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

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

    请按照此文档了解 EA 门户相关步骤。 Enable access to costs in the EA portal

【讨论】:

我不确定这是否正是问题所在,因为我已启用 EA 门户中的两个突出显示部分。我的应用程序服务主体也是计费读者,并且可以访问管理 API。我正在研究为应用程序服务主体提供具有适当权限的所有者,但还没有开始测试这个想法。

以上是关于身份验证令牌没有注册级别访问权限的主要内容,如果未能解决你的问题,请参考以下文章

如何在不经过注册用户身份验证的情况下保护公共API请求

OpenStack组件系列?Keystone

身份验证:是否可以使用Devise注册凭据来限制或授予对帖子模型的访问权限?

JWT 身份验证 - 为新注册的用户请求令牌时遇到问题

无需身份验证令牌即可访问 Google 电子表格 API

继续获得“超出未经验证的使用的每日限制”。持续使用需要注册“尝试谷歌加上我的网络应用程序登录