如何使用 StorageManagementClient 的客户端密码在服务/守护程序应用程序中获取 MSAL 令牌?

Posted

技术标签:

【中文标题】如何使用 StorageManagementClient 的客户端密码在服务/守护程序应用程序中获取 MSAL 令牌?【英文标题】:How do you get an MSAL token in a service/daemon app using client secret for StorageManagementClient? 【发布时间】:2021-12-05 15:04:12 【问题描述】:

我使用什么范围值来获取 C# 桌面框架 (4.8) 应用程序的身份验证令牌,该应用程序使用适用于 Azure 存储 API 的应用注册/客户端密钥?还是我需要做其他事情?在 MSAL 示例之后,我有这样的代码:

var authorityUri = new Uri($"https://login.microsoftonline.com/TenantId");
var app = Microsoft.Identity.Client.ConfidentialClientApplicationBuilder
    .Create(ApplicationId)
    .WithClientSecret(PrimaryClientSecretValue)
    .WithAuthority(authorityUri)
    .Build();
string[] scopes = new string[]  "https://graph.microsoft.com/.default" ;

AuthenticationResult result = null;
result = app.AcquireTokenForClient(scopes)
    .ExecuteAsync()
    .ConfigureAwait(false)
    .GetAwaiter()
    .GetResult();

var appSecretCredentials = new Microsoft.Rest.TokenCredentials(result.AccessToken, result.TokenType);
var storageManagementClient = new Microsoft.Azure.Management.Storage.StorageManagementClient(appSecretCredentials);
storageManagementClient.SubscriptionId = SubscriptionId;

var allStorageAccountsResponse = storageManagementClient.StorageAccounts
    .ListWithHttpMessagesAsync()
    .ConfigureAwait(false)
    .GetAwaiter()
    .GetResult();

var allStorageAccountsList = allStorageAccountsResponse.Body.ToArray();

Console.WriteLine("Storage account list");
foreach (var currStorageAccount in allStorageAccountsList)
    Console.WriteLine(currStorageAccount.Name);

这总是失败并显示“身份验证失败”。我尝试了以下范围值,但没有任何改进:https://management.azure.com、https://graph.microsoft.com/.default、https://graph.microsoft.com/.default、https://storage.azure.com、User.Read。使用多个作用域会更早地抛出。

如果我改为在 .NET Core 控制台应用程序中使用以下 ADAL 代码来获取令牌,则此 WORKS - 例如,我可以创建存储帐户:

var clientCredential    = new ClientCredential(clientId, clientSecret);
var context             = new AuthenticationContext("https://login.windows.net/" + tenantId);
var result              = context.AcquireTokenAsync("https://management.azure.com/", clientCredential)
                                .ConfigureAwait(false)
                                .GetAwaiter()
                                .GetResult();

var appSecretCredentials = new Microsoft.Rest.TokenCredentials(result.AccessToken);
var storageManagementClient = new Microsoft.Azure.Management.Storage.StorageManagementClient(appSecretCredentials);
storageManagementClient.SubscriptionId = subscriptionId;
// ...remainder as above...

在 Azure 门户|Active Directory|应用注册中,在身份验证下启用了允许公共客户端流,在 API 权限下,应用具有默认值 | Azure Storage\user_impersonation(唯一可用的权限)。在这两种情况下,我都使用 Microsoft.Identity.Client 4.36.2。

【问题讨论】:

【参考方案1】:

对于标准客户端凭据流,请使用 /.default。例如, https://graph.microsoft.com/.default。 Azure AD 将自动在客户端凭据流的访问令牌中包含管理员已同意的所有应用级权限。请求访问所有权限的范围。 如果您想获取所有静态范围应用程序的令牌,请将 .default 附加到 API 的应用程序 ID URI

ResourceId = "someAppIDURI";

var scopes = new []   ResourceId+"/.default";

范围应该是:- 范围:[“https://management.core.windows.net/.default”]

您也可以提供足够的权限。

阅读更多here。

【讨论】:

【参考方案2】:

谢谢!不幸的是,范围值不是它——我忘了​​列出我使用的所有范围字符串,那就是一个。企业应用程序的权限或同意也没有。我对很多东西进行了广泛的测试。

但是,我确实找到了原因:服务主体需要被授予对父资源组或目标存储帐户的贡献者权限(根据您的喜好)。由于 SP 已经拥有父资源组的所有者权限,这允许 SP 创建存储帐户,您会认为 SP 将能够在其在该 RG 中创建的存储帐户中创建 blob、容器等。事实并非如此。作为存储帐户的所有者应该足以让 SP 授予自己的贡献者权利来解决这个问题,但我还没有编写代码来做到这一点。

【讨论】:

以上是关于如何使用 StorageManagementClient 的客户端密码在服务/守护程序应用程序中获取 MSAL 令牌?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?