C# 如何使用Exchange Online/EWS管理的API对控制台应用程序进行身份验证?

C# 如何使用Exchange Online/EWS管理的API对控制台应用程序进行身份验证?,c#,exchangewebservices,ews-managed-api,outlook-2016,credential-manager,C#,Exchangewebservices,Ews Managed Api,Outlook 2016,Credential Manager,我正在开发一个供个人使用的控制台应用程序,该应用程序使用Exchange Web Services托管API作为赎回(遗憾的是,我无法使用)的替代方案。我的最终目标是在Windows计划任务中使用该应用程序连接到我的Exchange邮箱,并执行一些任务,如在一年中的特定时间创建文件夹、将电子邮件移动到这些文件夹、设置项目的保留策略等 该应用进展顺利,但我很好奇如何最好地为该应用实现安全认证,以便我可以在工作中使用它。我知道(不确定这是否包括现代身份验证…见下文),我必须明确地传递它们。在开发过程

我正在开发一个供个人使用的控制台应用程序,该应用程序使用Exchange Web Services托管API作为赎回(遗憾的是,我无法使用)的替代方案。我的最终目标是在Windows计划任务中使用该应用程序连接到我的Exchange邮箱,并执行一些任务,如在一年中的特定时间创建文件夹、将电子邮件移动到这些文件夹、设置项目的保留策略等

该应用进展顺利,但我很好奇如何最好地为该应用实现安全认证,以便我可以在工作中使用它。我知道(不确定这是否包括现代身份验证…见下文),我必须明确地传递它们。在开发过程中,我使用以下代码将用户ID和密码显式传递给Exchange:

string userId = UserPrincipal.Current.EmailAddress;
SecureString securePwd = new SecureString();

Console.Write("Current User ID/Email Address: {0}\n", userId);
Console.Write("Enter Password: ");

do
{
    key = Console.ReadKey(true);

    // Ignore the Backspace and Enter keys.
    if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
    {
        // Append the character to the password.
        securePwd.AppendChar(key.KeyChar);
        Console.Write("*");
    }
    else
    {
        if (key.Key == ConsoleKey.Backspace & securePwd.Length > 0)
        {
            securePwd.RemoveAt(securePwd.Length - 1);
            Console.Write("\b \b");
        }
        else if (key.Key == ConsoleKey.Enter)
        {
            break;
        }
    }
} while (true);

service.Credentials = new WebCredentials(new NetworkCredential(userId, securePwd));
我希望,由于我将创建我的Windows计划任务,无论用户是否登录,我都会选择
运行
选项,并输入我的密码,因此应用程序可以使用和传递计划任务使用的相同凭据,因此我根本不必存储密码,但我还没有找到任何允许这样做的东西

我的工作已启用Exchange Online的现代身份验证,并且在使用Outlook客户端时,它似乎会将我的Windows凭据传递给Exchange,而无需显式输入Outlook客户端的凭据。EWS管理的API中是否有类似的东西允许我的应用程序使用我的Windows凭据登录,而无需显式传递凭据?我知道你可以注册你的应用程序并使用OAuth,但我想避免这种情况,因为这是我个人使用的,我不确定我能否在工作中注册我的应用程序

如果无法实现上述功能,我已经看过很多文章,比如提到使用Windows凭据管理器的文章,这看起来很有希望,但似乎在存储密码之前,我还需要对密码做一些额外的操作。如果我在Windows凭据管理器中创建凭据,并使用下面的代码(并使用)在上面的链接上实现该代码,则密码将以纯文本显示

private const string PasswordName = "CredentialTest";

public static void Main(string[] args)
{
    LoadCredential();
    Console.ReadKey();
}

public static void LoadCredential()
{
    using (var cred = new CredentialManagement.Credential())
    {
        cred.Target = PasswordName;
        cred.Load();

        Console.WriteLine("Password: {0}", cred.Password);            
    }
}
是否建议将密码作为安全字符串读入,使用app.config文件加密部分中存储的密钥进行加密,然后将加密密码存储在Windows凭据管理器中

我遇到的另一个有趣的项目是EWS托管API中的
ClientCertificateCredentials
类。不幸的是,我还没有看到任何使用它的例子。这是另一种身份验证方法吗?此方法是否可以使用自签名证书?如果需要,是否需要在Exchange Online服务器上存储私钥

我对其他想法持开放态度,并感谢您的帮助


谢谢

Windows凭据管理器当然是一个选项(Outlook仍然存储POP3/IMAP4/SMTP密码并用于存储Exchange凭据)
请记住,Office 365将在2020年10月关闭基本身份验证。
OAuth可能是一个选项,但这意味着您仍然需要以某种方式提示用户输入凭据,并以某种方式存储访问和刷新令牌。
首选的解决方案是使用基于证书的身份验证-例如,请参阅

但这需要在服务器端导入证书,这需要管理员权限

这有点离题,但在OutlookSpy中,您如何在不让用户键入凭据的情况下调用EWS?我见过在VBA中使用XmlHttpRequest发送EWS SOAP请求的示例,但是这些示例都显式地设置了凭据。我很好奇,因为你提到微软将在2020年10月关闭基本身份验证,我想我可能能够实现一个替代方案,只使用VBA或使用COM加载项,就像你所做的那样,如果我可以使用登录用户的凭据。OutlookSpy修补WinHTTP函数并拦截身份验证令牌。我很抱歉猜测这不是我可以用VBA做的,对吗?是的,你需要C++或Delphi。理论上,您可以在C#中使用迂回,但我不喜欢在托管语言中使用迂回。好的,因此您不能单独使用VBA,必须使用C++/Delphi创建COM加载项来拦截身份验证令牌,对吗?您是否有关于如何使用C++/Delphi截获auth令牌的参考资料?