首页 > 解决方案 > 将系统分配的托管标识的委派权限分配给 Graph Api

问题描述

我正在尝试设置托管身份(系统分配),分配委托权限(如 Tasks.ReadWrite),然后使用它来调用 Graph Api。

我已经使用以下代码识别了对象 ID:

$app = Get-AzureADServicePrincipal -All $true -Filter "AppId eq '00000003-0000-0000-c000-000000000000'"
$role = $app.Oauth2Permissions | where-Object { $_.AdminConsentDisplayName -eq "Create, read, update, and delete user’s tasks and task lists" }

但是当我运行以下命令时:

New-AzureADServiceAppRoleAssignment -Id $role.Id -ObjectId $miObjectID -PrincipalId $miObjectID -ResourceId $app.ObjectId

其中 $miObjectID 是我的托管身份 ID,我收到以下错误消息:

New-AzureADServiceAppRoleAssignment : Error occurred while executing NewServicePrincipalAppRoleAssignment
Code: Request_BadRequest
Message: Permission being assigned was not found on application

标签: graphidentitymanaged

解决方案


我也尝试做同样的事情。我的理解是,这不是故意的。

通常,user-delegated权限应该以交互方式使用,涉及用户交互,例如在代表他访问用户资源的网络应用程序上。如果像我一样,您正在开发后端服务,这将不会成功。对于这种情况,支持的方法是只使用application权限并完成它。

但是,恕我直言,应用程序权限通常过于宽泛,授予对不相关资源的访问权限。例如,如果您的应用程序需要访问某个特定的 Sharepoint 站点,则您必须授权访问租户中的所有站点。应用程序权限不能限定范围。

由于合规原因,这是不可接受的。特别是如果您在 LOB 组织中工作。

尽管如此,我确实找到了一种解决方法,可以两全其美,即拥有真正的范围权限,并能够在后端服务中利用这些无人值守的权限。但有一个警告:我没有让它与托管标识一起使用,我必须使用常规服务主体。如果这是您可以接受的妥协,以下内容可能对您有所帮助。

  • 为此方案指定一个用户主体。根据需要授权该用户。选择一个最大长度的密码,即 256 个字符。启用 MFA。
  • 在 Azure AD 中创建应用/服务主体,生成客户端/应用凭据
  • 使用可用模板和 MSAL 库在本地创建演示 Web 应用程序。让上述应用向用户请求所需的用户委派权限
  • 然后,在应用程序代码中,使用资源所有者密码凭证、ROPC流对应用程序进行身份验证并承担用户的权限
    public class RessourceOwnerPasswordCredentialFlow
    {
        public static async Task<AccessToken> GetToken(HttpClient http, string credJson, Guid tenantId)
        {
            var ropc = credJson.Deserialize<GraphROPC>();
            var dict = new Dictionary<string, string>();
            dict.Add("grant_type", "password"); // ROPC
            dict.Add("username", ropc.User);
            dict.Add("password", ropc.Password);
            dict.Add("client_id", ropc.ClientId);
            dict.Add("client_secret", ropc.ClientSecret);
            dict.Add("scope", ".default");
            var url = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
            var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = new FormUrlEncodedContent(dict) };
            var res = await http.SendAsync(req);
            var content = await res.Content.ReadAsStreamAsync();
            var authResp = await content.DeserializeAsync<GraphAuthResponse>();
            return new AccessToken(authResp.access_token, DateTimeOffset.UtcNow.AddSeconds(authResp.expires_in));
        }
    }

    public class GraphROPC
    {
        public string User { get; set; }
        public string Password { get; set; }
        public string ClientId { get; set; }
        public string ClientSecret { get; set; }
    }

    public class GraphAuthResponse
    {
        public string token_type { get; set; }
        public string scope { get; set; }
        public int expires_in { get; set; }
        public string access_token { get; set; }
    }

注意:Microsoft不建议使用 ROPC 。

但是,我发现大多数反对意见不适用于我的情况。

  • 在后端服务应用程序中使用委派权限确实没有其他选择
  • 我绝对信任这款应用,因为它是我开发的
  • 该应用程序确实必须知道用户凭据,这些凭据存储在只有应用程序可以访问的 KeyVault 中(这次使用 MSI)
  • 此外,有人可能会争辩说,使用两组凭据,用户凭据加上应用程序凭据优于使用在使用(更多)应用程序权限时使用的客户端凭据。
  • ROPC 文档说,不支持具有 MFA 的用户帐户。但是,我可以确认,如果使用条件访问策略,则可以解决此限制。在我们的例子中,应用程序有一个固定的出站公共 IP 地址,可以添加为受信任的位置。事实上,如果缺少从 MFA 要求中将受信任位置列入白名单的能力,这将成为上述步骤的障碍。

推荐阅读