【问题标题】:How to enumerate Azure subscriptions and tenants programmatically?如何以编程方式枚举 Azure 订阅和租户?
【发布时间】:2017-06-24 15:31:48
【问题描述】:

如何以编程方式枚举 Azure 订阅和租户?这和我之前的问题Login-AzureRmAccount (and related) equivalent(s) in .NET Azure SDK有关。

基本上我尝试在桌面或控制台应用程序中复制Login-AzureRmAccountGet-AzureRmSubscription 的行为。到目前为止,我发现MSAL 似乎总是需要客户端 ID 和租户 ID,因此需要一些其他库来获取它们。在此之后,我想使用最新的库以编程方式创建服务主体,但我认为这是一个需要进一步调查的主题(如果需要,还可以提出问题)。

【问题讨论】:

    标签: azure .net-core azure-sdk-.net azure-ad-graph-api msal


    【解决方案1】:

    其实Login-AzureRmAccountGet-AzureRmSubscription使用Microsoft Azure PowerShell应用通过Resource Manager REST APIs操作Azure资源。

    要使用 REST 模拟与 PowersShell 命令相同的操作,我们也可以使用此应用程序。但是,由于此应用程序是在 Azure 门户(不是 v2.0 应用程序)上注册的,因此我们无法通过 MSAL 使用此应用程序获取令牌。我们需要使用Adal 而不是 MSAL。

    这是一个代码示例,用于通过Microsoft.WindowsAzure.Management 列出使用管理员帐户的订阅,供您参考:

    public static void ListSubscriptions()
    {
         string authority = "https://login.microsoftonline.com/common";
         string resource = "https://management.core.windows.net/";
         string clientId = "1950a258-227b-4e31-a9cf-717495945fc2";
        Uri redirectUri = new Uri("urn:ietf:wg:oauth:2.0:oob");
        AuthenticationContext authContext = new AuthenticationContext(authority);
        var access_token = authContext.AcquireTokenAsync(resource, clientId, redirectUri, new PlatformParameters (PromptBehavior.Auto)).Result.AccessToken;
    
        var tokenCred = new Microsoft.Azure.TokenCloudCredentials(access_token);
        var subscriptionClient = new SubscriptionClient(tokenCred);
        foreach (var subscription in subscriptionClient.Subscriptions.List())
        {
            Console.WriteLine(subscription.SubscriptionName);
        }
    }
    

    更新:

    string resource = "https://management.core.windows.net/";
    string clientId = "1950a258-227b-4e31-a9cf-717495945fc2";
    string userName = "";
    string password = "";
    
    HttpClient client = new HttpClient();
    string tokenEndpoint = "https://login.microsoftonline.com/common/oauth2/token";
    var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={userName}&password={password}";
    var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
    
    var result = client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>((response) =>
    {
        return response.Result.Content.ReadAsStringAsync().Result;
    }).Result;
    
    JObject jobject = JObject.Parse(result);
    var token = jobject["access_token"].Value<string>();
    
    client.DefaultRequestHeaders.Add("Authorization", $"bearer {token}");
    var subcriptions = client.GetStringAsync("https://management.azure.com/subscriptions?api-version=2014-04-01-preview").Result;
    
    Console.WriteLine(subcriptions);
    

    【讨论】:

    • 奇怪。我安装了 NuGet 包Microsoft.IdentityModel.Clients.ActiveDirectory 3.14.0,如果我制作var access_token = authContext.AcquireTokenAsync(resource, clientId, redirectUri, new Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters(PromptBehavior.Auto)).Result;,则没有这样的类。如果我排除PromptBehavior.Auto,我会得到NotImplementedException。虽然我看到它使用here 和其他地方。那会来自Microsoft.WindowsAzure.Management吗?
    • 这可能与我有一个 .NET Core 控制台应用程序有关,它可能缺少一些构造函数。我会在大约 12 小时后对此进行进一步检查,但对于您给出的示例(以及我对示例代码的困扰),.NET Core 可能是罪魁祸首。
    • @Veksi 上面的代码仅适用于 .Net 框架。根据测试,ADAL 没有实现Microsoft.IdentityModel.Clients.ActiveDirectory.WebUIFactory.CreateAuthenticationDialog(IPlatformParameters parameters)。如果您希望它支持 .net 核心,我建议您向 here 提出对 adal 库的反馈。
    • 我们也可以直接发送HTTP请求,而不是使用Microsoft.WindowsAzure.Management。以下是供您参考的请求:https://management.azure.com/subscriptions?api-version=2014-04-01-preview。作为此问题的解决方法,您可以使用资源所有者密码来获取访问令牌。我还更新了帖子中的代码示例。但是,此解决方法存在一些限制。例如,用户需要先授予应用程序的权限。这可能会建议 OP 使用 Login-AzureRmAccount 命令。而且这个流程也不支持 MFA。
    • 这很有帮助,我一定能取得一些进展。希望这也有助于其他人寻找答案。我想我会在 GH 中提出一个关于这个的问题(或者两个,另一个在 Fluent 中)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 2014-03-19
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    相关资源
    最近更新 更多