【问题标题】:How to authenticate a console application with Exchange Online/EWS Managed API?如何使用 Exchange Online/EWS 托管 API 对控制台应用程序进行身份验证?
【发布时间】:2019-10-25 13:21:51
【问题描述】:

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

该应用程序运行良好,但我很好奇如何最好地为该应用程序实施安全身份验证,以便我可以在工作中使用它。我知道Exchange Online won't let me connect automatically with default credentials(不确定这是否包括现代身份验证......见下文),我必须明确地传递它们。在开发过程中,我使用以下代码明确地将我的用户 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 计划任务并选择 Run whether user is logged on or not 选项并输入我的密码,所以应用程序可以使用并传递计划任务使用的相同凭据,所以我不必须存储我的密码,但我还没有找到任何允许这样做的东西。

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

如果上述方法不可行,我看过很多文章,例如 this one,其中提到使用 Windows 凭据管理器,看起来很有希望,但似乎我可能仍需要做一些额外的事情我存储之前的密码。如果我在 Windows 凭据管理器中创建凭据并使用下面的代码(并使用 CredentialManagement NuGet package)实现上面链接中的代码,则密码将以纯文本形式显示。

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 服务器上存储私钥?

我愿意接受其他想法并感谢您的帮助。

谢谢!

【问题讨论】:

    标签: c# exchangewebservices ews-managed-api outlook-2016 credential-manager


    【解决方案1】:

    Windows 凭据管理器当然是一个选项(这就是 Outlook 仍然存储 POP3/IMAP4/SMTP 密码并用于存储 Exchange 凭据的方式)。
    请注意,Office 365 将于 2020 年 10 月关闭基本身份验证。
    OAuth 可能是一种选择,但这意味着您仍然需要以某种方式提示用户输入凭据并以某种方式存储访问和刷新令牌。
    首选的解决方案是使用基于证书的身份验证 - 参见例如 https://developermessaging.azurewebsites.net/2018/09/11/authenticating-against-exchange-web-services-using-certificate-based-oauth2-tokens/
    但这需要在服务器端导入证书,这需要管理员权限。

    【讨论】:

    • 这有点离题了,但是在 OutlookSpy 中,您如何在不让用户键入其凭据的情况下调用 EWS?我见过在 VBA 中使用 XmlHttpRequest 发送 EWS SOAP 请求的示例,但这些示例都明确设置了凭据。我很好奇,因为您提到 Microsoft 将在 2020 年 10 月关闭基本身份验证,我想我可能可以使用 VBA 或使用 COM 加载项来实现替代方案,如果我可以使用任何一个登录用户的凭据。
    • OutlookSpy 修补 WinHTTP 函数并拦截身份验证令牌。
    • 我猜这不是我可以使用 VBA 做的事情,对吗?
    • 是的,您需要 C++ 或 Delphi。理论上,您可以在 C# 中使用 Detours,但我不喜欢在托管语言中这样做。
    • 好的,所以你不能单独使用 VBA 来完成,必须使用 C++/Delphi 创建一个 COM 插件来拦截身份验证令牌,对吗?您是否碰巧有关于如何使用 C++/Delphi 拦截身份验证令牌的参考资料?
    猜你喜欢
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多