在没有用户交互的情况下获取对 Graph API 的访问权限

Obtaining access to Graph API without user interaction

我是图表新手 API。我正在创建一个可以使用 Graph API 访问用户电子邮件的应用程序。我一直在使用 here.

中使用的设备令牌方法

以上代码适用于我的应用程序。但我想自动化这个过程。我从 Microsoft 文档中找到了一些帮助 here, from the sample codes here, and from this SO post.

但是我无法让我的代码自动获取令牌。我认为这是一个 API 权限问题,所以我将它们设置如下。

我能够获取 AcquireTokenInteractive,但 AcquireTokenSilent 不工作。

更新: 我设法得到一个异常消息是这样的“没有帐户或登录提示被传递给 AcquireTokenSilent 调用。”。还发现变量 FirstAccount 好像是空的。

下面是我获取token的代码。

using Azure.Core;
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System.Net.Http.Headers;

namespace DEA
{
    public class GraphHelper
    {
        private static GraphServiceClient? graphClient;
        private static AuthenticationResult token;
        
        private static IPublicClientApplication? application;        

        public static async void InitializeAuto(string ClientID, string InstanceID, string TenantID, string GraphUrl, string[] scopes)
        {
            string auth = string.Concat(InstanceID, TenantID);
            application = PublicClientApplicationBuilder.Create(ClientID)
                                        .WithAuthority(auth)
                                        .WithDefaultRedirectUri()
                                        .Build();

            try
            {
                var accounts = await application.GetAccountsAsync();

                graphClient = new GraphServiceClient(GraphUrl,
                    new DelegateAuthenticationProvider(async (requestMessage) =>
                    {
                        token = await application.AcquireTokenInteractive(scopes, accounts.FirstOrDefault()).ExecuteAsync();
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token.AccessToken);
                    }
                    ));
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception thrown: {0}", ex.Message);
            }  
        }
}

上述函数是从我的“Program.cs”调用的。

using DEA;
using Microsoft.Extensions.Configuration;

var appConfig = LoadAppSettings();

if (appConfig == null)
{
    Console.WriteLine("Set the graph API pemissions. Using dotnet user-secrets set .... They don't exsits in this computer.");
    return;
}

var appId = appConfig["appId"];
var TenantId = appConfig["TenantId"];
var Instance = appConfig["Instance"];
var GraphApiUrl = appConfig["GraphApiUrl"];
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };

GraphHelper.InitializeAuto(appId, Instance, TenantId, GraphApiUrl, scopes);

static IConfigurationRoot? LoadAppSettings()
{
    var appConfig = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .Build();

    // Check for required settings
    if (string.IsNullOrEmpty(appConfig["appId"]) ||
        string.IsNullOrEmpty(appConfig["scopes"]))
    {
        return null;
    }

    return appConfig;
}

我不知道我做错了什么。我用了一个 try ... catch 但仍然没有。我得到的唯一错误是当我按我的应用程序的选项 2 时图形客户端调用抛出的异常。

有人可以帮我解决这个问题吗?

能否重新开始并使用 AcquireTokenSilent() 重试,让我们看看是否有任何错误。

{
         var accounts = await application.GetAccountsAsync();
         result = await application.AcquireTokenSilent(scopes, 
         accounts.FirstOrDefault())
         .ExecuteAsync();
   }
   catch (MsalUiRequiredException ex)
   {
         result = await application.AcquireTokenInteractive(scopes)
         .WithClaims(ex.Claims)
         .ExecuteAsync();
   }

文档 - https://github.com/Azure-Samples/ms-identity-dotnet-desktop-tutorial/tree/master/1-Calling-MSGraph/1-1-AzureAD

阅读@Marc 和@Jeremy Lakeman 后,我使用 IConfidentialClientApplication 重写了代码。并使用 this 作为 Microsoft 指南的指南。

并想出了下面的代码,现在可以使用了。

public static async void InitializeAuto(string ClientID, string InstanceID, string TenantID, string GraphUrl, string ClientSecret, string[] scopes)
        {
            string auth = string.Concat(InstanceID, TenantID);

            application = ConfidentialClientApplicationBuilder.Create(ClientID)
                          .WithClientSecret(ClientSecret)
                          .WithAuthority(new Uri(auth))
                          .Build();

            Console.WriteLine("Auth: {0}", auth);
            Console.WriteLine("Client Secrets: {0}", ClientSecret);

            try
            {
                graphClient = new GraphServiceClient(GraphUrl,
                    new DelegateAuthenticationProvider(async (requestMessage) =>
                    {
                        AuthToken = await application.AcquireTokenForClient(scopes).ExecuteAsync();
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", AuthToken.AccessToken);
                    }
                    ));
                /*result = await application.AcquireTokenForClient(scopes)
                         .ExecuteAsync();

                Console.WriteLine("Token: {0}", result.AccessToken);*/
            }
            catch (MsalUiRequiredException ex)
            {
                // The application doesn't have sufficient permissions.
                // - Did you declare enough app permissions during app creation?
                // - Did the tenant admin grant permissions to the application?
                Console.WriteLine("Exception: {0}", ex.Message);
            }
            catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
            {
                // Invalid scope. The scope has to be in the form "https://resourceurl/.default"
                // Mitigation: Change the scope to be as expected.
                Console.WriteLine("Scope provided is not supported");
            }  
        }