20

我正在尝试使用 C#以编程方式检索HostedServicesMicrosoft.Azure.Management.Compute这需要ServiceClientCredential,我不知道如何得到它。

我怎样才能实例化这个类?

我可以使用它们,Microsoft.WindowsAzure.Management.Compute但在这里它只返回 ResourceManager 下的实例而不是经典实例。

4

4 回答 4

22

首先,您需要创建 Active Directory 应用程序。请参阅如何:使用门户创建可以访问资源的 Azure AD 应用程序和服务主体

下面的示例代码使用 nuget 包Microsoft.Azure.Management.Compute13.0.1-prerelease

public class CustomLoginCredentials : ServiceClientCredentials
{
    private string AuthenticationToken { get; set; }
    public override void InitializeServiceClient<T>(ServiceClient<T> client)
    {
        var authenticationContext = new AuthenticationContext("https://login.windows.net/{tenantID}");
        var credential = new ClientCredential(clientId: "xxxxx-xxxx-xx-xxxx-xxx", clientSecret: "{clientSecret}");

        var result = authenticationContext.AcquireToken(resource: "https://management.core.windows.net/", clientCredential: credential);

        if (result == null) throw new InvalidOperationException("Failed to obtain the JWT token");

        AuthenticationToken = result.AccessToken;
    }
    public override async Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request == null) throw new ArgumentNullException("request");

        if (AuthenticationToken == null) throw new InvalidOperationException("Token Provider Cannot Be Null");
        
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticationToken);
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        //request.Version = new Version(apiVersion);
        await base.ProcessHttpRequestAsync(request, cancellationToken);
    }
}

然后你可以像这样初始化客户端:

netClient = new Microsoft.Azure.Management.Compute.ComputeManagementClient(new CustomLoginCredentials());
netClient.SubscriptionId = _subscriptionId;
于 2016-05-31T13:07:21.183 回答
4

您现在执行此操作的方式是使用 ITokenProvider 和 Microsoft.Rest.TokenCredentials。

public class CustomTokenProvider : ITokenProvider
{
    private readonly CustomConfiguration _config;

    public CustomTokenProvider(CustomConfiguration config)
    {
        _config = config;
    }

    public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
    {
        // For app only authentication, we need the specific tenant id in the authority url
        var tenantSpecificUrl = $"https://login.microsoftonline.com/{_config.TenantId}/";

        // Create a confidential client to authorize the app with the AAD app
        IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
                                                                        .Create(_config.ClientId)
                                                                        .WithClientSecret(_config.ClientSecret)
                                                                        .WithAuthority(tenantSpecificUrl)
                                                                        .Build();
        // Make a client call if Access token is not available in cache
        var authenticationResult = await clientApp
            .AcquireTokenForClient(new List<string> { _config.Scope })
            .ExecuteAsync();


        return new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
    }
}

然后在您的 DI 配置中

services.AddTransient<IPowerBIClient, PowerBIClient>((provider) =>
{
    var config = provider.GetRequiredService<CustomConfiguration>();
    var tokenProvider = provider.GetRequiredService<CustomTokenProvider>();

    return new PowerBIClient(new Uri(config.BaseUrl), new TokenCredentials(tokenProvider));
});

我的示例与 Power BI 一起使用,但适用于需要访问 ServiceClientCredentials 的任何内容。

您可以将 Nuget 包 Microsoft.Identity.Client 用于 IConfidentialClientApplication。

于 2020-12-15T10:22:38.953 回答
3

稍后在游戏中,但这就是我们在项目中执行此操作的方式。我们使用 .net 框架提供的令牌凭据来访问托管身份、视觉工作室(代码)身份或交互式身份。并连接到 Azure 基础设施 API。

internal class CustomTokenProvider : ServiceClientCredentials
{
    private const string BearerTokenType = "Bearer";
    private TokenCredential _tokenCredential;
    private readonly string[] _scopes;
    private readonly IMemoryCache _cache;

    public CustomTokenProvider(TokenCredential tokenCredential, string[] scopes, IMemoryCache cache)
    {
        _tokenCredential = tokenCredential ?? throw new ArgumentNullException(nameof(tokenCredential));
        _scopes = scopes ?? throw new ArgumentNullException(nameof(scopes));
        _cache = cache;
    }

    public override async Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request == null)
        {
            throw new ArgumentNullException(nameof(request));
        }

        var token = await _cache.GetOrCreateAsync("accessToken-tokenProvider." + string.Join("#", _scopes), async e =>
        {
            var accessToken = await _tokenCredential.GetTokenAsync(new TokenRequestContext(_scopes), cancellationToken);
            e.AbsoluteExpiration = accessToken.ExpiresOn;
            return accessToken.Token;
        });
        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(BearerTokenType, token);
        await base.ProcessHttpRequestAsync(request, cancellationToken).ConfigureAwait(false);
    }
}

几点说明:

  • TokenCredential 类不缓存令牌,如果不这样做,则会由于请求过多而在 azure 上触发错误。
  • 使用 v2 调用调用 v1 端点需要在范围内有点创意。因此,当您需要访问管理 API 时,请提供以下范围“https://management.core.windows.net/.default”,而不是指定的 user_impersonate 范围。这是由于不同端点上的一些内部转换。并且“.default”范围始终可用,并将为您提供
于 2021-04-15T09:10:20.393 回答
2

正如@verbedr回答的那样,您可以TokenCredentialAzure.Identity 客户端库中调整一个。@antdev回答说你可以实现一个Microsoft.Rest.ITokenProvider. 另一种选择是将两种方法结合起来,如下所示:

using Azure.Core;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Rest
{
    /// Allows an Azure.Core.TokenCredential to be the Microsoft.Rest.ITokenProvider.
    public class TokenCredentialTokenProvider : Microsoft.Rest.ITokenProvider
    {
        readonly TokenCredential _tokenCredential;
        readonly string[] _scopes;

        public TokenCredentialTokenProvider(TokenCredential tokenCredential, string[] scopes)
        {
            _tokenCredential = tokenCredential;
            _scopes = scopes;
        }

        public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
        {
            var accessToken = await _tokenCredential.GetTokenAsync(new TokenRequestContext(_scopes), cancellationToken);
            return new AuthenticationHeaderValue("Bearer", accessToken.Token);
        }
    }
}

它没有缓存。CachingTokenProvider如果需要,您可以创建一个或类似的。这可以像这样使用:

            var tokenCredentials = new Azure.Identity.DefaultAzureCredential(new Azure.Identity.DefaultAzureCredentialOptions
            {
                AuthorityHost = Azure.Identity.AzureAuthorityHosts.AzurePublicCloud
            });

            var restTokenProvider = new Microsoft.Rest.TokenCredentialTokenProvider(tokenCredentials,
                new string[] { "https://management.core.windows.net/.default" }
            );

            var restTokenCredentials = new Microsoft.Rest.TokenCredentials(restTokenProvider);

            using var computeClient = new ComputeManagementClient(restTokenCredentials);
            // computeClient.BaseUri = // set if using another cloud
            computeClient.SubscriptionId = subscriptionId;
            var vms = computeClient.VirtualMachines.ListAll();
            Console.WriteLine("# of vms " + vms.Count());

这对我有用。以下是我使用的 csproj 中的相关依赖项:

    <PackageReference Include="Azure.Identity" Version="1.4.0" />
    <PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.23" />
    <PackageReference Include="Microsoft.Azure.Management.Compute" Version="46.0.0" />
于 2021-05-21T00:29:46.567 回答