Я отправлял почту через 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+.
Чтобы создать токен с помощью 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
, как показано ниже: