Microsoft Graph SDK - 将驱动器作为授权应用程序获取(非用户)
Microsoft Graph SDK - Get drives as authed app (Not user)
我在为 dotnet 核心应用程序从共享点(磁盘)检索数据时遇到一些问题。
目前我的应用程序尝试使用应用程序本身,而不是登录用户来检索磁盘,但首选方法是使用登录用户的访问令牌。
也许作为具有 clientId 和机密的应用程序进行身份验证根本无法与驱动器一起使用?
登录正常。
我已经使用以下启动设置了一个 dotnet 核心应用程序:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(30);
})
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
我还注册了以下服务:
services.AddTransient<IAuthenticationProvider, GraphAuthenticationProvider>();
services.AddTransient<IGraphServiceClient, GraphServiceClient>();
services.AddTransient<IGraphProvider, MicrosoftGraphProvider>();
我在哪里使用这个来验证:
public class GraphAuthenticationProvider : IAuthenticationProvider
{
public const string GRAPH_URI = "https://graph.microsoft.com/";
private string _tenantId { get; set; }
private string _clientId { get; set; }
private string _clientSecret { get; set; }
public GraphAuthenticationProvider(IConfiguration configuration)
{
_tenantId = configuration.GetValue<string>("AzureAd:TenantId");
_clientId = configuration.GetValue<string>("AzureAd:ClientId");
_clientSecret = configuration.GetValue<string>("AzureAd:ClientSecret");
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
AuthenticationContext authContext = new AuthenticationContext($"https://login.microsoftonline.com/{_tenantId}");
ClientCredential creds = new ClientCredential(_clientId, _clientSecret);
//I have tried using acquireTokensAsync with scopes, but there is no such method.
AuthenticationResult authResult = await authContext.AcquireTokenAsync(GRAPH_URI, creds);
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
}
}
我在门户的 API 设置中为该应用程序授予了足够的权限,主要是因为我不确定我需要什么,目前我只是急于让它先工作,然后再重构一些。
应用可以登录,并通过SDK获取以下数据:
var groups = await _graphServiceClient.Groups[appSettings.AzureAd.GroupId].Request().GetAsync();
但是:以下不起作用:
var groupDrives = await _graphServiceClient.Groups[appSettings.AzureAd.GroupId].Drives
.Request()
.GetAsync();
我收到以下错误:
代码:拒绝访问
消息:scp 或角色声明需要出现在令牌中。
我在启动时也有用户登录,如果不登录azure AD就无法使用该应用程序:
我可以改用用户的 accessToken 吗?
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };
options.TokenValidationParameters.ValidateIssuer = false;
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx =>
{
var roleGroups = new Dictionary<string, string>();
Configuration.Bind("AuthorizationGroups", roleGroups);
var clientApp = ConfidentialClientApplicationBuilder
.Create(Configuration["AzureAD:ClientId"])
.WithTenantId(Configuration["AzureAD:TenantId"])
.WithClientSecret(Configuration["AzureAD:ClientSecret"])
.Build();
var authResult = await clientApp
.AcquireTokenOnBehalfOf(new[] { "User.Read", "Group.Read.All" }, new UserAssertion(ctx.SecurityToken.RawData))
.ExecuteAsync();
var graphClient = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(async (requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);
}));
//Could i register the graphservice as a singelton with the users accesstoken?
//Fetching drives here with the accessToken from user works.
var graphService = new GraphService(graphClient, Configuration);
var memberGroups = await graphService.CheckMemberGroupsAsync(roleGroups.Keys);
var claims = memberGroups.Select(groupGuid => new Claim(ClaimTypes.Role, roleGroups[groupGuid]));
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
}
};
});
我实际上想使用用户访问令牌来检索驱动器等,但我不确定如何 store\reuse 访问令牌。我应该像评论中提到的那样使用用户 accesstoken 将服务注册为 singelton?
我遵循了本指南,它与我使用的 classes\services 相同:
http://www.keithmsmith.com/get-started-microsoft-graph-api-calls-net-core-3/
我实际上认为这里顶部的选项只是一个 header。现在可能更容易了.. https://i.imgur.com/yfZWaoe.png
您已经定义了委派范围,但正在尝试使用客户端凭据进行身份验证。委托范围之所以这样命名,是因为用户正在委托他们访问您的应用程序。
您需要在 authenticating without a User 时请求应用程序范围。
感觉你在这里混淆了一大堆概念。您使用的那个示例基于客户端凭据流。您可能应该首先阅读可用的不同类型的身份验证流程。 https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows
一般在使用客户端凭证流时,需要设置的权限是api权限边栏中的应用权限。委派权限用于用户登录流程。
当您像上面一样使用委派权限时。并且您使用获取用户令牌的流程,那么应用程序具有的访问权限基于用户具有的访问权限。例如,如果您使用委派权限委派 groups.read.all,则应用程序可以读取 该特定用户有权访问的所有组 。它不会让应用程序访问所有组。如果这是你想要的,那么一定要使用用户流程。
您没有提到您是否正在编写 Web 应用程序,或者是什么,但如果是,您可能需要仔细查看代理流程。这是一个例子。 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-1-Call-MSGraph
但以上再次适用于权限,当您获得用户令牌时,您的应用程序将只能访问用户有权访问的项目。不再。例如,用户 A 可以访问 Sharepoint 站点 A,用户 B 无法访问站点 A,当您使用用户令牌让用户 B 调用图形时,站点 A 不会 return 结果,因为用户 B 没有访问权限
我在为 dotnet 核心应用程序从共享点(磁盘)检索数据时遇到一些问题。 目前我的应用程序尝试使用应用程序本身,而不是登录用户来检索磁盘,但首选方法是使用登录用户的访问令牌。
也许作为具有 clientId 和机密的应用程序进行身份验证根本无法与驱动器一起使用?
登录正常。
我已经使用以下启动设置了一个 dotnet 核心应用程序:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(30);
})
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
我还注册了以下服务:
services.AddTransient<IAuthenticationProvider, GraphAuthenticationProvider>();
services.AddTransient<IGraphServiceClient, GraphServiceClient>();
services.AddTransient<IGraphProvider, MicrosoftGraphProvider>();
我在哪里使用这个来验证:
public class GraphAuthenticationProvider : IAuthenticationProvider
{
public const string GRAPH_URI = "https://graph.microsoft.com/";
private string _tenantId { get; set; }
private string _clientId { get; set; }
private string _clientSecret { get; set; }
public GraphAuthenticationProvider(IConfiguration configuration)
{
_tenantId = configuration.GetValue<string>("AzureAd:TenantId");
_clientId = configuration.GetValue<string>("AzureAd:ClientId");
_clientSecret = configuration.GetValue<string>("AzureAd:ClientSecret");
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
AuthenticationContext authContext = new AuthenticationContext($"https://login.microsoftonline.com/{_tenantId}");
ClientCredential creds = new ClientCredential(_clientId, _clientSecret);
//I have tried using acquireTokensAsync with scopes, but there is no such method.
AuthenticationResult authResult = await authContext.AcquireTokenAsync(GRAPH_URI, creds);
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
}
}
我在门户的 API 设置中为该应用程序授予了足够的权限,主要是因为我不确定我需要什么,目前我只是急于让它先工作,然后再重构一些。
应用可以登录,并通过SDK获取以下数据:
var groups = await _graphServiceClient.Groups[appSettings.AzureAd.GroupId].Request().GetAsync();
但是:以下不起作用:
var groupDrives = await _graphServiceClient.Groups[appSettings.AzureAd.GroupId].Drives
.Request()
.GetAsync();
我收到以下错误: 代码:拒绝访问 消息:scp 或角色声明需要出现在令牌中。
我在启动时也有用户登录,如果不登录azure AD就无法使用该应用程序: 我可以改用用户的 accessToken 吗?
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };
options.TokenValidationParameters.ValidateIssuer = false;
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx =>
{
var roleGroups = new Dictionary<string, string>();
Configuration.Bind("AuthorizationGroups", roleGroups);
var clientApp = ConfidentialClientApplicationBuilder
.Create(Configuration["AzureAD:ClientId"])
.WithTenantId(Configuration["AzureAD:TenantId"])
.WithClientSecret(Configuration["AzureAD:ClientSecret"])
.Build();
var authResult = await clientApp
.AcquireTokenOnBehalfOf(new[] { "User.Read", "Group.Read.All" }, new UserAssertion(ctx.SecurityToken.RawData))
.ExecuteAsync();
var graphClient = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(async (requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);
}));
//Could i register the graphservice as a singelton with the users accesstoken?
//Fetching drives here with the accessToken from user works.
var graphService = new GraphService(graphClient, Configuration);
var memberGroups = await graphService.CheckMemberGroupsAsync(roleGroups.Keys);
var claims = memberGroups.Select(groupGuid => new Claim(ClaimTypes.Role, roleGroups[groupGuid]));
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
}
};
});
我实际上想使用用户访问令牌来检索驱动器等,但我不确定如何 store\reuse 访问令牌。我应该像评论中提到的那样使用用户 accesstoken 将服务注册为 singelton?
我遵循了本指南,它与我使用的 classes\services 相同: http://www.keithmsmith.com/get-started-microsoft-graph-api-calls-net-core-3/
我实际上认为这里顶部的选项只是一个 header。现在可能更容易了.. https://i.imgur.com/yfZWaoe.png
您已经定义了委派范围,但正在尝试使用客户端凭据进行身份验证。委托范围之所以这样命名,是因为用户正在委托他们访问您的应用程序。
您需要在 authenticating without a User 时请求应用程序范围。
感觉你在这里混淆了一大堆概念。您使用的那个示例基于客户端凭据流。您可能应该首先阅读可用的不同类型的身份验证流程。 https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows
一般在使用客户端凭证流时,需要设置的权限是api权限边栏中的应用权限。委派权限用于用户登录流程。
当您像上面一样使用委派权限时。并且您使用获取用户令牌的流程,那么应用程序具有的访问权限基于用户具有的访问权限。例如,如果您使用委派权限委派 groups.read.all,则应用程序可以读取 该特定用户有权访问的所有组 。它不会让应用程序访问所有组。如果这是你想要的,那么一定要使用用户流程。
您没有提到您是否正在编写 Web 应用程序,或者是什么,但如果是,您可能需要仔细查看代理流程。这是一个例子。 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-1-Call-MSGraph
但以上再次适用于权限,当您获得用户令牌时,您的应用程序将只能访问用户有权访问的项目。不再。例如,用户 A 可以访问 Sharepoint 站点 A,用户 B 无法访问站点 A,当您使用用户令牌让用户 B 调用图形时,站点 A 不会 return 结果,因为用户 B 没有访问权限