Поток аутентификации Azure в настольном приложении (WinForms C#)

Я отправлял почту через SMTP (и читал через IMAP) через Azure, используя OAuth для настольного приложения (C# WinForms .NET Framework 4.8). Учетная запись имеет MFA, но это не учетная запись Windows. Я прочитал несколько статей, тем и примеров, но никто не подал заявку, и кажется невозможным завершить поток аутентификации пользователя, чтобы получить токен для учетной записи, если приложение не является веб-приложением.

Следующий код работает, но я не могу получить токен доступа для определенной учетной записи:

public static readonly string[] SCOPES = new string[] { "https://outlook.office.com/IMAP.AccessAsUser.All", "https://outlook.office.com/SMTP.Send", "https://outlook.office.com/User.Read" };
public static readonly string[] SCOPES_IMAP = { "https://outlook.office.com/IMAP.AccessAsUser.All" };


string oAuthTenantId = this.txtOAuthTenantId.Text;
string oAuthClientId = this.txtOAuthClientId.Text;
string oAuthSecret = this.txtOAuthSecret.Text;

IConfidentialClientApplication oAuthApp = ConfidentialClientApplicationBuilder.Create(oAuthClientId)
    .WithClientSecret(oAuthSecret)
    .WithAuthority(new Uri($"https://login.microsoftonline.com/{oAuthTenantId}"))
    .WithRedirectUri("https://localhost") 
    .Build();

var authUrl = oAuthApp.GetAuthorizationRequestUrl(SCOPES).ExecuteAsync().Result;
var accessToken = oAuthApp.AcquireTokenForClient(SCOPE_DEFAULT).ExecuteAsync().Result;

Я тоже использую веб-приложение, и там это «легко», я использую authUrl, чтобы перенаправить пользователя в поток аутентификации MS, но в настольном приложении я не знаю, как это сделать.

🤔 А знаете ли вы, что...
C# позволяет создавать приложения для разных платформ, включая Windows, Linux и macOS, с использованием .NET Core и .NET 5+.


53
1

Ответ:

Решено

Чтобы создать токен с помощью OAuth для настольного приложения (C# WinForms .NET Framework 4.8), вам необходимо переключиться на поток делегированной проверки подлинности, например интерактивный поток.

Для интерактивного потока обязательно добавьте URI перенаправления как http://localhost на платформе Mobile & desktop applications и включите опцию общедоступного клиентского потока при регистрации приложения, как показано ниже:

В моем случае я создал одно настольное приложение (C# WinForms .NET Framework 4.8) и использовал приведенные ниже примеры файлов кода для создания токена:

ОАутхелпер.cs:

using System.Linq;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

namespace OAuthWinFormsApp
{
    public class OAuthHelper
    {
        private static readonly string[] Scopes = new string[]
        {
            "https://outlook.office.com/IMAP.AccessAsUser.All",
            "https://outlook.office.com/SMTP.Send",
            "https://outlook.office.com/User.Read"
        };

        private IPublicClientApplication _pca;

        public OAuthHelper(string clientId, string tenantId)
        {
            _pca = PublicClientApplicationBuilder.Create(clientId)
                .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
                .WithRedirectUri("http://localhost")
                .Build();
        }

        public async Task<string> GetAccessTokenAsync()
        {
            AuthenticationResult result = null;

            try
            {
                var accounts = await _pca.GetAccountsAsync();
                result = await _pca.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
                    .ExecuteAsync();
            }
            catch (MsalUiRequiredException)
            {
                result = await _pca.AcquireTokenInteractive(Scopes)
                    .WithPrompt(Prompt.SelectAccount)
                    .ExecuteAsync();
            }

            return result.AccessToken;
        }
    }
}

Форма1.cs:

using System;
using System.Windows.Forms;

namespace OAuthWinFormsApp
{
    public partial class Form1 : Form
    {
        private OAuthHelper _oauthHelper;

        public Form1()
        {
            InitializeComponent();
            _oauthHelper = new OAuthHelper("appId", "tenantId");
        }


        private async void btnAuthenticate_Click(object sender, EventArgs e)
        {
            try
            {
                string token = await _oauthHelper.GetAccessTokenAsync();
                txtToken.Text = token;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error: {ex.Message}", "Authentication Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void txtToken_TextChanged(object sender, EventArgs e)
        {

        }
    }
}

Выход:

Когда я декодировал токен на веб-сайте jwt.ms, он имеет значения утверждений aud и scp, как показано ниже: