graph - 将系统分配的托管标识的委派权限分配给 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
解决方案
我也尝试做同样的事情。我的理解是,这不是故意的。
通常,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 要求中将受信任位置列入白名单的能力,这将成为上述步骤的障碍。
推荐阅读
- elixir - 使用管道与函数调用时的错误/混淆
- assembly - 跨越缓存线如何影响循环的解码方式?
- html - 如何防止查询 >>> 正在加载的表上?Django 表
- android - 项目更新推荐:Android Gradle Plugin 可以升级。错误消息:在构建文件中找不到 AGP 版本
- unit-testing - 如何在模拟对象的方法中调用 CountDownLatch.countDown()
- c - 从 C 中的 csv 文件读取导致输入不打印
- mysql - 每个客户一个实例 - Sequelize 和 MySQL
- r - 从 R 中的数据框中替换或删除 � 和 "\xd0"
- python - Osmnx 将大图保存为 graphml
- html - HTML/CSS - 处理拒绝垂直居中的内容