使用客户端密钥获取适配StorageManagementClient的MSAL令牌及scope取值问题
Azure存储管理API MSAL认证问题解决方案
正确Scope值
你当前使用的是Microsoft.Azure.Management.Storage库,属于Azure资源管理器(ARM)的管理面接口,对应的MSAL客户端凭证流Scope值为https://management.azure.com/.default。
对应规则:ADAL中的
resource参数值末尾追加/.default,即可得到MSAL客户端凭证流的Scope值,你ADAL代码中使用的resource是https://management.azure.com/,因此对应MSAL Scope就是https://management.azure.com/.default。
你之前尝试的Scope错误原因如下:
https://graph.microsoft.com/.default:用于调用Microsoft Graph接口,和ARM管理接口无关https://storage.azure.com:用于调用Azure存储的数据平面接口(比如上传下载Blob),不适用于存储账户的管理操作User.Read:属于Microsoft Graph的委托权限,不支持服务主体的客户端凭证流- 未加
/.default后缀的资源地址:不符合MSAL客户端凭证流的规范要求,会直接触发异常
需要调整的配置项
- API权限配置
你当前配置的Azure Storage\user_impersonation是存储数据平面的委托权限,仅适用于用户登录场景下的存储数据操作,不满足服务主体管理存储账户的需求:
- 进入应用注册的「API权限」页,删除原有配置的Azure Storage权限
- 添加「Azure 服务管理」的应用权限,权限名称为
user_impersonation - 点击「授予管理员同意」完成权限激活
- RBAC角色分配
进入你的Azure订阅/对应资源组的「访问控制(IAM)」页,将当前应用注册对应的服务主体添加为「存储账户贡献者」或「参与者」角色,否则即使认证成功也没有权限操作存储资源 - 可选优化配置
你当前开启的「允许公共客户端流」是为桌面/移动等无密钥的公共客户端场景准备的,你使用客户端密钥的机密客户端流不需要该配置,可手动关闭,不影响现有逻辑运行。
修正后的核心代码
仅需要调整Scope数组的定义即可:
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://management.azure.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);
内容的提问来源于stack exchange,提问作者David Luxford
相关产品推荐
相关产品推荐

