我将使用桌面应用程序的 OAuth (C# WinForms .NET Framework 4.8) 通过 Azure 上的 SMTP 发送邮件(并通过 IMAP 读取)。该帐户具有 MFA,但不是 Windows 帐户。我读过一些文章、主题和示例,但没有人适用,并且如果应用程序不是 Web,则似乎不可能完成用户身份验证流程以获取帐户的令牌。
以下代码有效,但我无法获取特定帐户的 accessToken:
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 身份验证流程,但在桌面应用程序中,我不知道该怎么做。
要使用 OAuth 为桌面应用程序 (C# WinForms .NET Framework 4.8) 生成令牌,您需要切换到委托身份验证流程,如交互流程。
对于交互式流程,请确保在
Mobile & desktop applications
平台中将重定向 URI 添加为 http://localhost,并在应用程序注册中添加 enable 公共客户端流程选项,如下所示:
就我而言,我创建了一个桌面应用程序(C# WinForms .NET Framework 4.8)并使用以下示例代码文件来生成令牌:
OAuthHelper.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;
}
}
}
Form1.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
声明值,如下所示: