c# - 无法通过基本 C# 应用程序的 Azure 身份验证

标签 c# azure authentication azure-ad-graph-api

我刚刚开始使用 Azure,我的第一次尝试是使用图形客户端 API 进行简单的数据显示。简单来说,我想获取员工的 Teams 状态并以某种图形方式将其显示在表单上。

我试图尽可能基本,所以当我尝试下载示例时,我不需要 UWP 项目,只需要基本的 winform(控制台目前可以工作)。我确实从项目中借用了一些东西来编译,但我收到错误:

MsalUiRequiredException:没有帐户或登录提示传递到 AcquireTokenSilent 调用。

这是完整的代码,我显然遗漏了一些东西......什么?这是一个应用程序,应该能够访问 Graph API 以获取用户读取和 getPresence 调用以显示当前状态,并需要使用登录。我可以看到 Graph Explorer 有一个 token 并正在查看 postman 集有一些方法可以在没有交互的情况下做到这一点,但没有一个文档是明确的。我将继续研究这个问题,也许看看我是否可以让 postman 工作,这可能会有所帮助,但幕后的访问权限对我来说并不清楚。

    public partial class Form1 : Form

{
    //Set the scope for API call to user.read
    private string[] scopes = new string[] { "user.read" };

    private const string ClientId = "my client id";

    private const string Tenant = "my tenant id"; 
    private const string Authority = "https://login.microsoftonline.com/" + Tenant;

    // The MSAL Public client app
    private static IPublicClientApplication PublicClientApp;

    private static string MSGraphURL = "https://graph.microsoft.com/v1.0/";
    private static AuthenticationResult authResult;
    public Form1()
    {
        InitializeComponent();
        PublicClientApp = PublicClientApplicationBuilder.Create(ClientId).WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient").Build();

        callMe();
    }
    private async void callMe()
    {
        // Sign-in user using MSAL and obtain an access token for MS Graph
        GraphServiceClient graphClient = await SignInAndInitializeGraphServiceClient(scopes);

        // Call the /me endpoint of Graph
        User graphUser = await graphClient.Me.Request().GetAsync();

        Console.WriteLine(graphUser.Id);

        var graphu2 = await graphClient.Users["my email address"].Request().GetAsync();

    }
    private async Task<GraphServiceClient> SignInAndInitializeGraphServiceClient(string[] scopes)
    {
    
            GraphServiceClient graphClient = new GraphServiceClient(MSGraphURL,
            new DelegateAuthenticationProvider(async (requestMessage) =>
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await getToken(scopes));
            }));

        return await Task.FromResult(graphClient);
    }
    public async Task<string> getToken(string[] scopes)
    {
        PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
                         .WithAuthority(Authority)
                         .WithLogging((level, message, containsPii) =>
                         {
                             Console.WriteLine($"MSAL: {level} {message} ");
                         }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
                        .Build();

        IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
        IAccount firstAccount = accounts.FirstOrDefault();

        try
        {
            authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
                                              .ExecuteAsync();
        }
        catch (MsalUiRequiredException ex)
        {
            // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
            Console.WriteLine($"MsalUiRequiredException: {ex.Message}");

            authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
                                              .ExecuteAsync()
                                              .ConfigureAwait(true);

        }
        return authResult.AccessToken;

    }

最佳答案

抱歉,但我将忽略您的代码并将其分解为更简单的代码。

using Azure.Identity;
using Microsoft.Graph;

namespace StackoverflowAnswer
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MainAsync().Wait();
        }

        static async Task MainAsync()
        {
            var tenantId = "YOUR_TENANT_ID";
            var clientId = "YOUR_CLIENT_ID";
            var clientSecret = "YOUR_CLIENT_SECRET";

            try
            {
                string[] scopes = { "https://graph.microsoft.com/.default" };

                ClientSecretCredential clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);

                GraphServiceClient graphClient = new GraphServiceClient(clientSecretCredential, scopes);

                var users = await graphClient.Users.Request().GetAsync();

                foreach (var user in users)
                    Console.WriteLine(user.UserPrincipalName);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

上面的许多代码都取自以下文档,因为一旦您通过身份验证,SDK 的其余部分就基本相同。不过,这可能会很棘手,具体取决于您想做的事情的具体性质......

https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/docs/tokencredentials.md

这也有帮助......

https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider

另请确保您已在 Azure 门户中为应用程序分配了所需的 API 权限...

API Permissions

...并确保您已为您的应用程序设置了客户端 key 。如果您有客户端 ID,那么您显然已经做到了这一点...

https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app

更新

现在,对于使用 Presence API,这有点棘手。

虽然看起来如此,但 Presence API 不支持应用程序权限。它有一个应用程序权限,但简单地说,它不起作用。此用户语音链接提供了对此的见解。

https://techcommunity.microsoft.com/t5/microsoft-365-developer-platform/graph-api-presence-should-support-application-permissions/idi-p/2276109

因此,您需要做的是将委派权限应用到您注册的应用程序。

App Permissions

因此,您需要在代码中使用 UsernamePasswordCredential 而不是 ClientSecretCredential,并在实例化 GraphServiceClient 时替换它。

UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredential("<USERNAME>", "<PASSWORD>", tenantId, clientId);

此外,您需要确保相关用户已授予使用该权限的访问权限。如果它是面向用户的应用程序,那么他们会登录并看到一个问题,以批准您设置的权限,但因为它不是,所以您需要转到企业应用程序部分Azure AD,找到您的应用,转到权限,然后为您的租户按下授予管理员同意按钮。

有人可能有比上面更好的方法,但这是我能找到的唯一方法。这意味着如果有人知道客户端 ID 以及如何进行身份验证,他们就可以执行与您相同的 API。

无论如何,这将允许您了解码织中所有用户的状态。

关于c# - 无法通过基本 C# 应用程序的 Azure 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74146546/

相关文章:

Android Studio 1.1.0 Facebook SDK 登录

azure - 使用 Azure devops 中的 Azure powershell 任务向 Azure Keyvault 添加/获取 key

azure - 控制触发器 blob App Function Azure

c# - MVVM DynamicObject + Entity Framework STE 实体 + 属性更改行为

c# - WebBrowser 控件和嵌入标记

azure - 我可以使用 Azure Migrate 工具将 IBM MQ 从本地迁移到 Azure 云吗

c# - 如何处理 Xamarin Forms 的 Azure 移动应用程序中的用户 token ?

authentication - 与 OAuth 相比,OpenID OAuth 扩展有哪些优势?

c# - Java 与 .NET 中的 DES 加密——为什么不同?

c# - 接口(interface)在类之间通信