我在Azure VM上有一个Exchange Online环境和服务/ daemin(无交互式用户)应用程序。服务使用EWS托管API来处理任何租户用户邮箱中的电子邮件。现在,EWS客户端使用基本身份验证,根据Microsoft的说法,EWS将不再支持EWS客户端访问Exchange Online。
因此,我需要找到一种方法,以获取与EWS托管API一起使用的服务/守护程序应用程序的有效访问令牌。
以下article显示了将OAuth 2.0与EWS托管API结合使用的示例。此示例有效,但是它使用交互式方法来获取同意(登录表单出现,允许用户进行身份验证并向应用程序授予请求的权限),该方法不适用于服务/守护程序应用程序场景,因为没有交互式用户。
对于服务/守护程序应用程序,我需要使用client credential
身份验证流程。
在https://aad.portal.azure.com门户上使用管理员帐户我在Azure Active Directory中注册了应用程序。为注册的应用程序添加了客户端机密。
上述article使用https://outlook.office.com/EWS.AccessAsUser.All
作为scope
。但是我没有在门户网站上找到具有此类URL的许可。我在Office 365 Exchange Online
> Application permissions
> Mail
下仅发现以下权限:
https://outlook.office365.com/Mail.Read
允许该应用在没有登录用户的情况下读取所有邮箱中的邮件https://outlook.office365.com/Mail.ReadWrite
允许该应用在没有登录用户的情况下创建,读取,更新和删除所有邮箱中的邮件。 我添加了这两者,并为所有用户授予了管理员同意。
出于测试目的和简便起见,我没有使用任何身份验证库(ADAL,MSAL等)。我使用Postman获取访问令牌,然后在调试中设置token
变量(请参阅后面的代码片段)。
我尝试了不同的端点来获取访问令牌。
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
发送此请求会产生以下错误响应:
AADSTS70011:提供的请求必须包含“作用域”输入参数。输入参数“ scope”提供的值无效。范围https://outlook.office.com/EWS.AccessAsUser.All无效。
我尝试将scope
更改为https://outlook.office.com/.default
。访问令牌已返回,但对于EWS似乎无效。 EWS客户端使用以下值x-ms-diagnostics
响应标头引发401错误:
2000008; reason =“该令牌不包含权限,或者权限无法理解。”; error_category =“ invalid_grant”
POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/token
grant_type=client_credentials
client_id=***
client_secret=***
resource=https://outlook.office.com
访问令牌已返回,但对于EWS也似乎无效。 EWS客户端抛出401错误,其响应标头值与x-ms-diagnostics
中的var token = "...";
var client = new ExchangeService
{
Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx"),
Credentials = new OAuthCredentials(token),
ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,
"user@domain.onmicrosoft.com"),
};
var folder = Folder.Bind(client, WellKnownFolderName.SentItems);
相同。
这是我用来用Postman中获得的访问令牌测试EWS客户端的代码示例:
keepOrder = (a, b) => {
return a;
}
答案 0 :(得分:2)
您可以使用证书或密码来保护客户端应用程序。要使其正常工作,我需要两个许可权:Calendars.ReadWrite.All
和full_access_as_app
。我从未尝试通过 PostMan 获取令牌,而是在AcquireTokenAsync
中使用Microsoft.IdentityModel.Clients.ActiveDirectory
。在该调用中,我使用的resource
参数是https://outlook.office365.com/。一旦您知道所有小小的曲折,就非常简单。并全面披露:直到MSFT支持帮助我完成这项工作之前,我还是一只迷失的小狗。网络上的文档经常过时,冲突或充其量是令人困惑的。
答案 1 :(得分:2)
我们遇到了类似的问题:我们想使用服务帐户连接到单个邮箱,并且仅使用EWS API进行一些操作(例如在GAL中搜索),而full_access_as_app
似乎是一个过大的杀伤力。
幸运的是,有可能:
遵循常规的"delegate" steps
并使用它通过用户名/密码获取令牌:
...
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();
...
通过该设置,我们可以使用“传统的”用户名/密码方式,但可以使用OAuth和EWS API。
答案 2 :(得分:1)
您需要在Azure中注册您的应用并使用基于证书的身份验证。 https://blogs.msdn.microsoft.com/emeamsgdev/2018/09/11/authenticating-against-exchange-web-services-using-certificate-based-oauth2-tokens/
答案 3 :(得分:0)
在关注OAuth 2.0 client credentials flow的Microsoft官方文档时遇到了同样的问题
根据Microsoft identity platform and the OAuth 2.0 client credentials flow,范围“应为所需资源的资源标识符(应用程序ID URI),并带有.default后缀”(请参见default scope doc)。
所以问题是如何将https://outlook.office.com/EWS.AccessAsUser.All
转换为资源标识符。
实验上,我设法使用scope=https://outlook.office365.com/.default
使它工作。我授予了full_access_as_app
(Office 365 Exchange Online /应用程序权限)和got administrator consent。
答案 4 :(得分:0)
在为EWS实施OAuth时确实遇到了这个问题。我的应用程序是使用EWS Managed API的 not 。这是我所做的所有工作。
Office 365 Exchange Online > full_access_as_app
。https://outlook.office365.com/.default
的访问令牌。POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
form-data = {
client_id,
client_secret,
grant_type: 'client_credentials',
scope: 'https://outlook.office365.com/.default',
};
Authorization
标头和ExchangeImpersonation
SOAP标头添加到请求中。<SOAP-ENV:Header>
<t:ExchangeImpersonation>
<t:ConnectingSID>
<t:PrimarySmtpAddress>user@domain.com</t:PrimarySmtpAddress>
</t:ConnectingSID>
</t:ExchangeImpersonation>
</SOAP-ENV:Header>
答案 5 :(得分:0)
最新答案,但是由于这似乎要解决,而我只是在处理此问题……为什么不这样做。
如果您将Microsoft v2.0 URL用于OAUTH2(https://login.microsoftonline.com/common/oauth2/v2.0/authorize
和.../common/oauth2/v2.0/token
),则Office 365 EWS的范围是:
https://outlook.office365.com/EWS.AccessAsUser.All
您可能需要将此范围与“ openid”(以获取已登录用户的身份)和“ offline_access”(以获取刷新令牌)结合使用。但是,在使用客户端凭据时,也许不需要offline_access(因为您不必在每次需要访问令牌时都提示人类用户)。
换句话说:
params.add("client_id", "...")
...
params.add("scope", "openid offline_access https://outlook.office365.com/EWS.AccessAsUser.All")
如果使用v1 OAUTH2 URL(https://login.microsoftonline.com/common/oauth2/authorize
和.../common/oauth2/token
),则可以使用“资源”而不是“范围”。 Office 365的资源为https://outlook.office365.com/
。
或者换句话说:
params.add("resource", "https://outlook.office365.com/")
请注意,在后一种情况下,您不需要任何作用域(不可能将“资源”与作用域结合使用)。但是令牌会自动覆盖offline_access和openid范围。
答案 6 :(得分:0)
我成功使用了此方法:
安装Microsoft身份验证库模块(MSAL.PS) https://www.powershellgallery.com/packages/MSAL.PS/4.2.1.3
按照MSFT指令配置代理访问权限:https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
正常配置服务帐户的ApplicationImpersonation
获取令牌
$ cred =获取凭据
$ clientid =“”
$ tenantid =“”
$ tok = Get-MsalToken -ClientId $ clientid -TenantId $ tenantid -UserCredential $ cred -Scopes“ https://outlook.office.com/EWS.AccessAsUser.All”