使用 Oauth2 进行身份验证以读取 C# MVC 网络应用程序中的 IMAP

问题描述

我想使用 IMAP 阅读来自已登录用户的电子邮件

我创建了一个控制台应用程序用于测试目的,并确保 azure 中的应用程序注册设置正确。

控制台应用程序按预期工作。

  1. 显示 Microsoft 登录窗口,用户可以在其中输入凭据。
  2. 收到访问令牌并将其传递给 MailKit 以获取用户的电子邮件

问题

当我尝试在 MVC .net 标准 Web 应用程序中使用 MailKit 进行身份验证时,我收到一条错误消息,提示“身份验证失败”。

但是,当我复制使用控制台应用程序获取的访问令牌并在我的 Web 应用程序中使用它时,我没有收到授权错误,并且可以成功地进行身份验证和阅读电子邮件。 (我使用访问令牌作为第二个参数 var oauth2 = new SaslMechanismOAuth2("[Email here]",oathToken.access_token);).

我使用了 DotNetOpenAuth显示 Microsoft 登录窗口。 (我找不到 Web 应用程序的 MSAL 示例,我不必将 OWIN 添加为中间件。我只想进行身份验证以获取电子邮件,而不是应用程序范围的身份验证和授权。)

控制台应用程序代码(有效):

             // Using Microsoft.Identity.Client 4.22.0

             // Configure the MSAL client to get tokens
            var pcaOptions = new PublicclientApplicationoptions
             {
                 ClientId = "[client-id here]",AadAuthorityAudience = AadAuthorityAudience.AzureAdMultipleOrgs,};

            var pca = PublicclientApplicationBuilder
                .CreateWithApplicationoptions(pcaOptions).Build();

            var scopes = new string[] {
                 "email","offline_access","https://outlook.office365.com/IMAP.AccessAsUser.All" };

            // Make the interactive token request
            var authResult = await pca.AcquiretokenInteractive(scopes).ExecuteAsync();

            var oauth2 = new SaslMechanismOAuth2(authResult.Account.Username,authResult.Accesstoken);

            using (var client = new ImapClient())
            {
                await client.ConnectAsync("outlook.office365.com",993,SecureSocketoptions.Auto);
                await client.AuthenticateAsync(oauth2);

                var inBox = client.InBox;
                inBox.Open(FolderAccess.ReadOnly);

                for (int i = 0; i < inBox.Count; i++)
                {
                    var message = inBox.GetMessage(i);
                    Console.WriteLine("Subject: {0}",message.Subject);
                }

                await client.disconnectAsync(true);
            }

Web 应用程序(这不起作用):

public ActionResult Index()
    {
        string clientID = "[client-id here]";
        string clientSecret = "[client-secret here]";
        string redirectUri = "[redirectUri here]";

        AuthorizationServerDescription server = new AuthorizationServerDescription
        {
            AuthorizationEndpoint = new Uri("https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize"),TokenEndpoint = new Uri("https://login.microsoftonline.com/organizations/oauth2/v2.0/token"),ProtocolVersion = ProtocolVersion.V20,};

        List<string> scopes = new List<string>
        {
           "email","https://outlook.office365.com/IMAP.AccessAsUser.All"
        };

        WebServerClient consumer = new WebServerClient(server,clientID,clientSecret);

        OutgoingWebResponse response = consumer.PrepareRequestUserAuthorization(
        scopes,new Uri(redirectUri));

        return response.AsActionResultMvc5();
    }

    public async Task<ActionResult> Authorized(string code,string state,string session_state)
    {
        List<string> scopes = new List<string>
        {
            "IMAP.AccessAsUser.All","User.Read","offline_access"
        };

        HttpClient httpClient = new HttpClient();

        var values = new Dictionary<string,string>
        {
            { "Host","https://login.microsoftonline.com" },{ "Content-Type","application/x-www-form-urlencoded" },{ "client_id","[client-id here]" },{ "scope",string.Join(" ",scopes) },{ "code",code },{ "redirect_uri",[redirectUri here] },{ "grant_type","authorization_code" },{ "client_secret","[client-secret here]" },{ "state",state },};

        var content = new FormUrlEncodedContent(values);

        var response = await httpClient.PostAsync("https://login.microsoftonline.com/organizations/oauth2/v2.0/token",content);


        var jsonString = await response.Content.ReadAsstringAsync();
        var oathToken = JsonConvert.DeserializeObject<OathToken>(jsonString);

        var oauth2 = new SaslMechanismOAuth2("[Email here]",oathToken.access_token);
        var stringBuilder = new StringBuilder();

        using (var client = new ImapClient())
        {
            try
            {
                await client.ConnectAsync("outlook.office365.com",SecureSocketoptions.Auto);
                await client.AuthenticateAsync(oauth2);

                var inBox = client.InBox;
                inBox.Open(FolderAccess.ReadOnly);

                for (int i = 0; i < inBox.Count; i++)
                {
                    var message = inBox.GetMessage(i);
                    stringBuilder.AppendLine($"Subject: {message.Subject}");
                }

                await client.disconnectAsync(true);

                return Content(stringBuilder.ToString());

            }
            catch (Exception e)
            {
                return Content(e.Message);
            }

        }
    }

问题出现在这一行:await client.AuthenticateAsync(oauth2); 我收到一条错误消息,提示“身份验证失败” 但是,在 Web 应用程序中使用来自控制台应用程序的访问令牌时,我没有收到此错误,并且可以在 Web 应用程序中成功验证和读取电子邮件

谁能指出我正确的方向?

谢谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)