首页 > 解决方案 > Microsoft Graph SDK - 将驱动器作为经过身份验证的应用程序(非用户)

问题描述

我在为 dotnet 核心应用程序从共享点(磁盘)检索数据时遇到一些问题。目前我的应用程序尝试使用应用程序本身,而不是登录用户来检索磁盘,但首选方法是使用登录用户的 accesstoken 代替

也许使用 clientId 和 secret 认证为应用程序根本不适用于驱动器?

登录工作正常。

我已经使用以下启动设置了一个 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>();

我在哪里使用 this 进行身份验证:

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();

我收到以下错误:代码:AccessDenied 消息:令牌中需要存在 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);

                    }
                };
            });

我实际上想使用用户访问令牌来检索驱动器等,但我不确定如何存储\重用访问令牌。如评论中所述,我可能应该使用用户访问令牌将服务注册为单项?

我遵循了本指南,它具有我使用过的相同的类\服务:http: //www.keithmsmith.com/get-started-microsoft-graph-api-calls-net-core-3/

我实际上认为这里顶部的选项只是一个标题。现在可能更容易了.. https://i.imgur.com/yfZWaoe.png

标签: .net-coreoauth-2.0azure-active-directorymicrosoft-graph-apimicrosoft-graph-sdks

解决方案


感觉就像你在这里混淆了一大堆概念。您使用的示例基于客户端凭据流。您可能应该首先阅读可用的不同类型的身份验证流程。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 有权访问共享点站点 A,用户 B 无权访问站点 A,当您使用用户 B 的用户令牌调用图形时,它不会返回站点 A 的结果,因为用户 B 无权访问它。


推荐阅读