如何从WPF应用程序中的azure AD应用程序获取用户姓名列表?

问题描述 投票:0回答:1

我正在构建一个 WPF 应用程序,我想在单击按钮或在下拉列表中时从 Azure AD 应用程序检索所有用户的名称。我在 ASP.NET Core Web API 中编写了一个 HttpGet 方法来实现此目的,并使用 Postman(使用 OAuth 2.0)对其进行了测试,我可以成功地看到所有用户的名称。但是,当我从 WPF 应用程序调用 HttpGet 端点时,我遇到了错误。

这是我的 HttpGet 端点,它在 Postman 中测试时从 Azure AD 应用程序返回所有用户的名称(OAuth 2.0,其中我提供了客户端 ID、客户端密码、范围等)-

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly ILogger<UsersController> _logger;

    public UsersController(ITokenAcquisition tokenAcquisition, ILogger<UsersController> logger)
    {
        _tokenAcquisition = tokenAcquisition;
        _logger = logger;
    }

    [HttpGet]
    public async Task<IActionResult> GetUsers()
    {
        try
        {
            var token = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "User.ReadBasic.All", "User.Read" });
            var graphClient = new GraphServiceClient(new AuthProvider(token));

            var usersList = new List<string>();
            var usersPage = await graphClient.Users
                .Request()
                .Select(u => new { u.DisplayName })
                .GetAsync();

            usersList.AddRange(usersPage.Select(u => u.DisplayName));

            while (usersPage.NextPageRequest != null)
            {
                usersPage = await usersPage.NextPageRequest.GetAsync();
                usersList.AddRange(usersPage.Select(u => u.DisplayName));
            }

            return Ok(usersList);

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An error occurred while fetching users.");
            return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while fetching users.");
        }
    }

    private class AuthProvider : IAuthenticationProvider
    {
        private readonly string _token;
        public AuthProvider(string token)
        {
            _token = token;
        }
        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
            await Task.CompletedTask;
        }
    }
}

在我的WPF应用程序中调用API(我不确定我是否使用了正确的方法)-

public partial class MainWindow : Window
{
    private static readonly HttpClient client = new HttpClient();
    private static IConfidentialClientApplication confidentialClientApp;

    public MainWindow()
    {
        InitializeComponent();

        // Initialize MSAL ConfidentialClientApplication with client secret
        confidentialClientApp = ConfidentialClientApplicationBuilder.Create("47......")
            .WithClientSecret("gF......")
            .WithAuthority(AzureCloudInstance.AzurePublic, "d81e......")
            .WithRedirectUri("http://localhost")
            .Build();
    }

    private async void FetchDataButton_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            // Acquire token silently
            string[] scopes = new string[] { "api://47....../.default" };
            AuthenticationResult authResult = await confidentialClientApp.AcquireTokenForClient(scopes).ExecuteAsync();

            // Set the token in the request header
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);

            // Make the HTTP GET request
            string apiUrl = "https://localhost:7159/api/Users";
            var response = await client.GetAsync(apiUrl);

            if (response.IsSuccessStatusCode)
            {
                string responseData = await response.Content.ReadAsStringAsync();
                MessageBox.Show(responseData, "API Response", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                MessageBox.Show("Error: " + response.ReasonPhrase, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        catch (MsalException msalEx)
        {
            MessageBox.Show("Authentication error: " + msalEx.Message, "Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
        catch (Exception ex)
        {
            MessageBox.Show("Exception: " + ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
}

但我收到一个错误 - MsalUiRequiredException:AADSTS50058:已发送静默登录请求,但没有用户登录。

我可以做什么来调用此 HttpGet 端点并在我的 WPF 应用程序中显示用户名列表?

wpf azure microsoft-graph-api asp.net-core-webapi desktop-application
1个回答
0
投票

就我而言,我注册了一个应用程序并公开了一个具有如下范围的 API:

enter image description here

在 API 权限选项卡中,我添加了适用于客户端凭据流程的

Application
类型的 User.Read.All 权限:

enter image description here

现在,我创建了另一个名为

MyWpfApp
的应用程序,并授予了公开的 API 权限,如下所示:

enter image description here

请查找以下适用于我的案例的代码示例:

UsersController.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;
using Microsoft.Identity.Web;
using Microsoft.Kiota.Abstractions.Authentication;
using Microsoft.Kiota.Abstractions;

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    private readonly ITokenAcquisition _tokenAcquisition;

    public UsersController(ITokenAcquisition tokenAcquisition)
    {
        _tokenAcquisition = tokenAcquisition;
    }

    [HttpGet]
    public async Task<IActionResult> GetUsers()
    {
        try
        {
            var token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default");
            var graphClient = new GraphServiceClient(new AuthProvider(token));

            // Fetch users with displayName
            var users = await graphClient.Users.GetAsync((requestConfiguration) =>
            {
                requestConfiguration.QueryParameters.Select = new string[] { "displayName" };
            });

            if (users == null || users.Value == null)
            {
                return StatusCode(500, "Error retrieving users: Users response is null");
            }

            var usersList = users.Value
                .Where(u => u.DisplayName != null)
                .Select(u => u.DisplayName)
                .ToList();

            return Ok(usersList);
        }
        catch (System.Exception ex)
        {
            return StatusCode(500, $"Error retrieving users: {ex.Message}");
        }
    }

    private class AuthProvider : IAuthenticationProvider
    {
        private readonly string _token;

        public AuthProvider(string token)
        {
            _token = token;
        }

        public Task AuthenticateRequestAsync(RequestInformation request, Dictionary<string, object>? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
        {
            request.Headers.Add("Authorization", $"Bearer {_token}");
            return Task.CompletedTask;
        }
    }
}

当我运行上述 API 时,我可以通过调用以下端点成功检索用户:

GET https://localhost:7261/api/Users

回复:

enter image description here

要在单击按钮时在 WPF 应用程序中获得相同的响应,您可以使用以下示例代码文件:

MainWindow.xaml:

<Window x:Class="MyWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My WPF App" Height="350" Width="525">
    <Grid>
        <Button Name="FetchDataButton" Content="Fetch Users" Click="FetchDataButton_Click" Width="150" Height="40" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" />
        <ListBox Name="UsersListBox" Width="400" Height="200" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,60,0,0" />
    </Grid>
</Window>

MainWindow.xaml.cs:

using Microsoft.Identity.Client;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Windows;

namespace MyWpfApp
{
    public partial class MainWindow : Window
    {
        private static readonly HttpClient client = new HttpClient();
        private static IConfidentialClientApplication confidentialClientApp;  

        public MainWindow()
        {
            InitializeComponent();
            
            confidentialClientApp = ConfidentialClientApplicationBuilder.Create("wpfappId")
                .WithClientSecret("wpfappsecret")
                .WithAuthority(new Uri("https://login.microsoftonline.com/tennatId"))
                .Build();
        }

        private async void FetchDataButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string[] scopes = { "api://myuserapiappId/.default" };
                AuthenticationResult authResult = await confidentialClientApp.AcquireTokenForClient(scopes).ExecuteAsync();

                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);

                string apiUrl = "https://localhost:7261/api/Users";
                var users = await client.GetFromJsonAsync<string[]>(apiUrl);

                UsersListBox.Items.Clear();
                if (users != null)
                {
                    foreach (var user in users)
                    {
                        UsersListBox.Items.Add(user);
                    }
                }
                else
                {
                    MessageBox.Show("No users found.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            catch (MsalException msalEx)
            {
                MessageBox.Show("Authentication error: " + msalEx.Message, "Authentication Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }
}

回复:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.