使用应用程序身份访问 Azure Graph API
Accessing the Azure Graph API using Application Identity
我正在使用 Azure Graph API,我注意到我无法读取通过许可框架注册的目录。
一切都适用于用户级权限。也就是说,用
private async Task<string> AcquireGraphApiTokenAsync(string objectId, AuthenticationContext authContext)
{
var result = await authContext.AcquireTokenSilentAsync(
GraphUrl, _clientCredential, new UserIdentifier(objectId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
我可以读取客户端数据如下:
var authority = string.Format(CultureInfo.InvariantCulture, AadInstance, tenantId);
var authContext = new AuthenticationContext(authority, new TokenDbCache(userObjectId));
var graphServiceRoot = GraphUrl + '/' + tenantId;
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), async () => await AcquireGraphApiTokenAsync(userObjectId, authContext));
try
{
var adUser = await graphClient.Me.ExecuteAsync();
...
}
然而,有时我想 运行 在守护进程中进行类似的处理,这就是我遇到麻烦的地方。在这种情况下,我需要使用我的应用程序标识:
private void AuditDirectories(ClientCredential clientCredential, IEnumerable<AzureActiveDirectory> directories)
{
foreach (var directory in directories)
{
var authContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, AadInstance, directory.Domain));
var result = authContext.AcquireToken(GraphUrl, clientCredential);
var graphServiceRoot = string.Format("{0}/{1}", GraphUrl, directory.TenantId);
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), () => Task.FromResult(result.AccessToken));
foreach (var user in _userQuery.Office365Users(directory))
{
CheckThatAccountExistsAndIsEnabled(graphClient, user);
}
}
}
传入的clientCredential
参数是从我的多租户应用程序的Client ID和Client Secret中获得的。
我的应用程序具有委派权限 "Read Directory Data" 和 "Enable sign-on and read user's profiles"。它具有应用程序权限 "Read Directory Data" 和 "Read and Write Directory Data",尽管我并不真的需要后者。但是,这不允许我查询图表 API。所有用户查询,例如
graphClient.Users.Where(u => u.DisplayName == userName).ExecuteAsync().Result.CurrentPage.FirstOrDefault()
抛出错误"Insufficient privileges to complete the operation"。
看起来使用用户身份的委托访问没有任何问题,但是使用应用程序身份访问失败,尽管我已经在应用程序级别设置了应用程序权限。
我认为这个问题目前的形式具有误导性。您可以作为用户和应用程序身份获取令牌 - 您可以使用 AcquireToken
和 AcquireTokenSilent
来完成这两件事。可以在目录中配置应用程序以请求不同的权限,具体取决于它们是使用应用程序身份访问资源还是使用用户身份进行委托访问。
在您的示例中,您在 AcquireTokenSilent
调用中作为用户获取令牌,在 AcquireToken
调用中作为应用程序获取令牌,并且您在应用程序中为这两种情况配置的不同权限导致你观察到的行为差异。但是,这种差异是由您使用的重载决定的,而不是由 AcquireTokenSilent
和 AcquireToken
.
之间的任何固有差异决定的
您可以通过门户中的应用程序权限下拉列表(而不是委托权限)将您的应用程序配置为可以访问 Azure AD Graph API,但请注意,您需要成为租户管理员能够这样做。
这似乎无缘无故地开始工作。虽然我很想说这是魔法造成的,但可能还有另一种解释。
正如vibronet所解释的那样,您需要为应用程序添加应用程序权限。完成此操作后,租户管理员有必要再次签署同意框架。我在一个单独的浏览器中执行此操作,作为应用程序应该读取其目录的租户的管理员。但是,我在设置应用程序权限后的几分钟内就这样做了。一天后,当我再次通过同意框架时,该应用程序再次开始工作。
如果您 运行 遇到与我描述的情况类似的情况,并且您需要更改应用程序权限下拉列表,请在您的租户通过许可之前花几分钟时间进行传播框架。 (我假设您将至少拥有一个您是其管理员的客户租户,以便您可以测试您的应用程序。)
我正在使用 Azure Graph API,我注意到我无法读取通过许可框架注册的目录。
一切都适用于用户级权限。也就是说,用
private async Task<string> AcquireGraphApiTokenAsync(string objectId, AuthenticationContext authContext)
{
var result = await authContext.AcquireTokenSilentAsync(
GraphUrl, _clientCredential, new UserIdentifier(objectId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
我可以读取客户端数据如下:
var authority = string.Format(CultureInfo.InvariantCulture, AadInstance, tenantId);
var authContext = new AuthenticationContext(authority, new TokenDbCache(userObjectId));
var graphServiceRoot = GraphUrl + '/' + tenantId;
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), async () => await AcquireGraphApiTokenAsync(userObjectId, authContext));
try
{
var adUser = await graphClient.Me.ExecuteAsync();
...
}
然而,有时我想 运行 在守护进程中进行类似的处理,这就是我遇到麻烦的地方。在这种情况下,我需要使用我的应用程序标识:
private void AuditDirectories(ClientCredential clientCredential, IEnumerable<AzureActiveDirectory> directories)
{
foreach (var directory in directories)
{
var authContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, AadInstance, directory.Domain));
var result = authContext.AcquireToken(GraphUrl, clientCredential);
var graphServiceRoot = string.Format("{0}/{1}", GraphUrl, directory.TenantId);
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), () => Task.FromResult(result.AccessToken));
foreach (var user in _userQuery.Office365Users(directory))
{
CheckThatAccountExistsAndIsEnabled(graphClient, user);
}
}
}
传入的clientCredential
参数是从我的多租户应用程序的Client ID和Client Secret中获得的。
我的应用程序具有委派权限 "Read Directory Data" 和 "Enable sign-on and read user's profiles"。它具有应用程序权限 "Read Directory Data" 和 "Read and Write Directory Data",尽管我并不真的需要后者。但是,这不允许我查询图表 API。所有用户查询,例如
graphClient.Users.Where(u => u.DisplayName == userName).ExecuteAsync().Result.CurrentPage.FirstOrDefault()
抛出错误"Insufficient privileges to complete the operation"。
看起来使用用户身份的委托访问没有任何问题,但是使用应用程序身份访问失败,尽管我已经在应用程序级别设置了应用程序权限。
我认为这个问题目前的形式具有误导性。您可以作为用户和应用程序身份获取令牌 - 您可以使用 AcquireToken
和 AcquireTokenSilent
来完成这两件事。可以在目录中配置应用程序以请求不同的权限,具体取决于它们是使用应用程序身份访问资源还是使用用户身份进行委托访问。
在您的示例中,您在 AcquireTokenSilent
调用中作为用户获取令牌,在 AcquireToken
调用中作为应用程序获取令牌,并且您在应用程序中为这两种情况配置的不同权限导致你观察到的行为差异。但是,这种差异是由您使用的重载决定的,而不是由 AcquireTokenSilent
和 AcquireToken
.
您可以通过门户中的应用程序权限下拉列表(而不是委托权限)将您的应用程序配置为可以访问 Azure AD Graph API,但请注意,您需要成为租户管理员能够这样做。
这似乎无缘无故地开始工作。虽然我很想说这是魔法造成的,但可能还有另一种解释。
正如vibronet所解释的那样,您需要为应用程序添加应用程序权限。完成此操作后,租户管理员有必要再次签署同意框架。我在一个单独的浏览器中执行此操作,作为应用程序应该读取其目录的租户的管理员。但是,我在设置应用程序权限后的几分钟内就这样做了。一天后,当我再次通过同意框架时,该应用程序再次开始工作。
如果您 运行 遇到与我描述的情况类似的情况,并且您需要更改应用程序权限下拉列表,请在您的租户通过许可之前花几分钟时间进行传播框架。 (我假设您将至少拥有一个您是其管理员的客户租户,以便您可以测试您的应用程序。)