如何在服务/守护程序应用程序中获取 EWS 托管 API 的 OAuth2 访问令牌

Ole*_*sii 7 c# exchangewebservices oauth-2.0 office365

设想

我在 Azure VM 上有一个 Exchange Online 环境和服务/daemin(无交互用户)应用程序。服务使用 EWS 托管 API 来处理任何租户用户邮箱中的电子邮件。现在 EWS 客户端使用基本身份验证,据 Microsoft 称,EWS 将不支持该身份验证来访问 Exchange Online。

问题/问题

因此,我需要找到一种方法来获取服务/守护程序应用程序的有效访问令牌以与 EWS 托管 API 一起使用。

我的发现

以下文章展示了将 OAuth 2.0 与 EWS 托管 API 结合使用的示例。此示例有效,但它使用了不适合服务/守护程序应用程序场景的交互式方法来获得同意(出现登录表单,允​​许用户验证自己并授予应用程序请求的权限),因为没有交互式用户。

对于服务/守护程序应用程序,我需要使用client credential身份验证流程。

注册申请

使用https://aad.portal.azure.com门户上的管理员帐户,我向 Azure Active Directory 注册了应用程序。为已注册的应用程序添加了客户端机密。

上述文章使用https://outlook.office.com/EWS.AccessAsUser.Allscope。但是我没有在门户网站上找到这样一个 URL 的许可。我发现只有在以下权限Office 365 Exchange Online> Application permissions> Mail

  1. https://outlook.office365.com/Mail.Read 允许应用在没有登录用户的情况下阅读所有邮箱中的邮件
  2. https://outlook.office365.com/Mail.ReadWrite 允许应用在没有登录用户的情况下创建、读取、更新和删除所有邮箱中的邮件。

我添加了它们并为所有用户授予管理员同意。

获取访问令牌

出于测试目的和简单起见,我没有使用任何身份验证库(ADAL、MSAL 等)。我使用 Postman 获取访问令牌,然后token在调试中设置变量(请参阅帖子后面的代码片段)。

我尝试了不同的端点来获取访问令牌。

  1. OAuth 2.0 令牌端点 (v2)
    POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token
        grant_type=client_credentials
        client_id=*** 
        client_secret=***
        scope=https://outlook.office.com/EWS.AccessAsUser.All
Run Code Online (Sandbox Code Playgroud)

发送此请求会产生以下错误响应:

AADSTS70011:提供的请求必须包含“范围”输入参数。为输入参数“范围”提供的值无效。范围https://outlook.office.com/EWS.AccessAsUser.All无效。

我尝试更改scopehttps://outlook.office.com/.default. 访问令牌已返回,但它似乎对 EWS 无效。EWS 客户端使用以下x-ms-diagnostics响应标头值引发 401 错误:

2000008;reason="令牌不包含权限,或者权限无法理解。";error_category="invalid_grant"

  1. OAuth 2.0 令牌端点 (v1)
    POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/token
        grant_type=client_credentials
        client_id=*** 
        client_secret=***
        resource=https://outlook.office.com
Run Code Online (Sandbox Code Playgroud)

访问令牌已返回,但似乎对 EWS 无效。EWS 客户端抛出 401 错误,x-ms-diagnostics响应标头的值与#1 中描述的相同。

将获得的访问令牌与 EWS 托管 API 结合使用

这是我用来使用 Postman 中获取的访问令牌测试 EWS 客户端的代码示例:

    POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token
        grant_type=client_credentials
        client_id=*** 
        client_secret=***
        scope=https://outlook.office.com/EWS.AccessAsUser.All
Run Code Online (Sandbox Code Playgroud)

Rob*_*sig 6

我们遇到了类似的问题:我们想使用服务帐户连接到单个邮箱,然后仅使用 EWS API 执行一些操作(例如在 GAL 中搜索),这full_access_as_app似乎有点矫枉过正。幸运的是,这是可能的:

  1. 遵循正常的“委托”步骤

  2. 并使用它通过用户名/密码获取令牌:

...
var cred = new NetworkCredential("UserName", "Password");
var authResult = await pca.AcquireTokenByUsernamePassword(new string[] { "https://outlook.office.com/EWS.AccessAsUser.All" }, cred.UserName, cred.SecurePassword).ExecuteAsync();
...
Run Code Online (Sandbox Code Playgroud)
  1. 要实现此功能,您需要在“身份验证”>“高级设置”下启用“将应用程序视为公共客户端”,因为这使用“资源所有者密码凭据流”。(这个答案对我帮助很大!)

通过该设置,我们可以使用“传统”用户名/密码方式,但使用 OAuth 和 EWS API。