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

  1. 一般在使用客户端凭证流时,需要设置的权限是api权限边栏中的应用权限。委派权限用于用户登录流程。

  2. 当您像上面一样使用委派权限时。并且您使用获取用户令牌的流程,那么应用程序具有的访问权限基于用户具有的访问权限。例如,如果您使用委派权限委派 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 没有访问权限