【问题标题】:How can I use Managed Service Identity falling back to my Azure credentials locally in Visual Studio with advanced permissions to Microsoft Graph如何在具有 Microsoft Graph 高级权限的 Visual Studio 中本地使用托管服务标识回退到我的 Azure 凭据
【发布时间】:2019-06-13 23:32:21
【问题描述】:

我正在使用图形 API 来检索用户图像和 SharePoint 列表项,并使用托管服务身份进行身份验证。 我成功地使用 powershell 为我的服务身份添加了所需的权限。

<#
ERRORS OUT BUT WORKS. YOU CAN VALIDATE BY USING THE GRAPH EXPLORER TO CALL: 
https://graph.microsoft.com/beta/servicePrincipals/{msiObjectId}/appRoleAssignedTo
NOTE: Get-AzureADServiceAppRoleAssignedTo DOES NOT WORK, MUST USE GRAPH EXPLORER FOR VALIDATION
#>

Connect-AzureAD

$msiObjectId = "12345678-1234-1234-1234-123456789101"
$app_name = "Microsoft Graph"
$role_names = @("Sites.Read.All", "User.Read.All", "Directory.Read.All")

$sp = Get-AzureADServicePrincipal -Filter "displayName eq '$app_name'"

$role_names | foreach {
    $role_name = $_
    $appRole = $sp.AppRoles | Where-Object { ($_.DisplayName -eq $role_name) -or ($_.Value -eq $role_name) }
    New-AzureADServiceAppRoleAssignment -ObjectId $msiObjectId -PrincipalId $msiObjectId -ResourceId $sp.ObjectId -Id $appRole.Id
}

Disconnect-AzureAD

当我将应用程序发布到分配给服务标识的天蓝色服务时,此错误但添加了权限并且工作正常。

我正在使用 Microsoft.Azure.Services.AppAuthentication 来检索令牌并进行调用。

using Microsoft.Azure.Services.AppAuthentication;
...
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await new AzureServiceTokenProvider().GetAccessTokenAsync("00000003-0000-0000-c000-000000000000"));
...

问题出在本地开发中,这取决于我的凭据。这成功地获得了一个具有一些基本图形访问权限的令牌,例如 /me 和 /user basic,但是当我尝试检索列表或用户图像时,我收到以下错误:

{
  "error": {
    "code": "accessDenied",
    "message": "The caller does not have permission to perform the action.",
    "innerError": {
      "request-id": "55555555-1234-1234-1234-123456789101",
      "date": "2019-06-12T17:05:31"
    }
  }
}

我已经尝试在 powershell 代码中使用我自己的对象 ID 代替 $msiObjectId,并且还尝试将 New-AzureADServiceAppRoleAssignment 更改为 New-AzureADUserAppRoleAssignment,但都没有成功。我还在 UI 中尝试了所有可能的方法,但找不到添加权限的方法,并尝试了 https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize?client_id=00000003-0000-0000-c000-000000000000&amp;scope=offline_access%20User.Read.All%20Sites.Read.All,这给了我一个关于没有回复 url 的错误,也不起作用。

我想我可能需要为我的帐户添加一些委托权限来代替应用程序角色分配,但无论如何我都找不到这样做。我可以使用$sp.Oauth2Permissions 查看权限,但无法找到授予自己这些权限的方法。

这可能吗?如果可以,怎么做?

基本上,我需要我的凭据(没有应用程序)在使用 new AzureServiceTokenProvider().GetAccessTokenAsync()) 时至少具有对 Microsoft Graph (GraphAggregatorService) 的“Sites.Read.All”和“User.Read.All”访问权限

【问题讨论】:

    标签: azure powershell permissions microsoft-graph-api acs-serviceidentity


    【解决方案1】:

    我在制作本地使用 AzureServiceTokenProvider 调用我自己的 API 的示例时遇到了这个问题。 正如您所注意到的,问题是本地获取的令牌是委托令牌这一事实。 在 Azure 中,它是一个仅限应用程序的令牌。

    您不能将应用权限分配给用户,除非 appRoles 允许的成员类型包括用户和应用程序。 那将是一件很奇怪的事情。 MS Graph API 不这样做。

    所以您需要一个仅限应用的令牌。

    在本地,您最好的选择可能是使用 MSAL 获取带有客户端凭据的令牌,并仅在 Azure 中使用 AzureServiceTokenProvider。 然后,您将获得一个类似于您在 Azure 中获得的令牌,具有应用权限等。

    【讨论】:

      【解决方案2】:

      @juunas 感谢您的确认。我最终为我的本地开发环境注册了一个应用程序,我将使用它在本地获取令牌。我将我的客户端 ID 和客户端机密保存在我的用户机密 (secrets.json) 中,以将其排除在我的部署之外,并使用这两个值的存在来确定是否将应用令牌与这些或服务标识一起使用.

      private async Task<string> GetDevTokenAsync()
      {
          var clientID = _configuration.GetValue<string>("AppSettings:ClientID") ?? _configuration.GetValue<string>("Authentication:AppSettings:ClientID");
          var clientSecret = _configuration.GetValue<string>("AppSettings:ClientSecret") ?? _configuration.GetValue<string>("Authentication:AppSettings:ClientSecret");
          if (string.IsNullOrWhiteSpace(clientID) || string.IsNullOrWhiteSpace(clientSecret))
              return null;
      
          using (var RestClient = new HttpClient())
          {
              var content = new FormUrlEncodedContent(
                  new[]
                      {
                          new KeyValuePair<string, string>("client_id", clientID),
                          new KeyValuePair<string, string>("client_secret", clientSecret),
                          new KeyValuePair<string, string>("scope", "https://graph.microsoft.com/.default"),
                          new KeyValuePair<string, string>("grant_type", "client_credentials")
                      }
                      );
              var response = await RestClient.PostAsync($"https://login.microsoftonline.com/{_tenantId}/oauth2/v2.0/token", content);
              return !response.IsSuccessStatusCode ? null : JObject.Parse(await response.Content.ReadAsStringAsync())?.Property("access_token")?.Value?.ToString();
          }
      }
      
      ...
      
      request.Headers.Authorization = new AuthenticationHeaderValue("Bearer",
          await GetDevTokenAsync() ?? 
          await new AzureServiceTokenProvider().GetAccessTokenAsync("00000003-0000-0000-c000-000000000000"));
      ...
      

      【讨论】:

        猜你喜欢
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-24
        • 2023-01-12
        • 2018-10-26
        • 2020-08-10
        • 1970-01-01
        相关资源
        最近更新 更多