我的网络服务目前正在进行基本的用户名/密码验证,以便订阅交换用户接收事件(如新邮件事件等),如下所示:
var service = new ExchangeService(exchangeVersion)
{
KeepAlive = true,
Url = new Uri("some autodiscovery url"),
Credentials = new NetworkCredential(username, password)
};
var subscription = service.SubscribeToPushNotifications(
new[] { inboxFolderFoldeID },
new Uri("some post back url"),
15,
null,
EventType.NewMail,
EventType.Created,
EventType.Deleted,
EventType.Modified,
EventType.Moved,
EventType.Copied);
现在,我应该更换身份验证机制以使用OAuth协议。我看到了一些示例,但所有这些示例似乎都在讨论对客户端进行身份验证(https://msdn.microsoft.com/en-us/library/office/dn903761%28v=exchg.150%29.aspx?f=255&MSPPError=-2147217396),但我无法找到如何使用OAuth协议对Exchange用户进行身份验证的示例。任何代码示例都会有很大帮助。感谢。
答案 0 :(得分:4)
目前尚不清楚您对“网络服务”的意思以及您目前如何获取用户名和密码。如果这是用户需要登录或传递凭据的某种类型的网站,那么您必须从浏览器启动OAuth2授权,如将客户端浏览器重定向到授权端点以启动implicit grant或{{ 3}}。一旦用户登录代码或访问令牌(取决于授权),用户将在OAuth2服务器(而不是您的应用程序)中显示登录屏幕,将返回到您可以在{{{{{ 1}}构造函数。
如果'web'服务是在用户计算机上运行的某项服务,则可以使用下述方法之一。
使用AuthenticationContext获取AccessToken
该示例似乎基于较早版本的code grant类。
AuthenticationContext
似乎更新,ExchangeService
现已重命名为AcquireToken
/ AcquireTokenAsync
。
无论您使用哪个版本,都无法像当前代码那样传递用户名和密码。但是,您可以让AcquireTokenSilentAsync
方法提示输入凭据给用户。说实话,让您的应用程序直接处理这些用户机密更安全。在您知道之前,您将在数据库中存储纯文本密码(希望您还没有)。
在这两个版本中,这些方法都有很多重载,所有重载都有不同的参数和略有不同的功能。对于您的用例,我认为这些很有趣:
AcquireToken[Async]
可以是IPlatformParameters
AcquireTokenAsync(string, string, Uri, IPlatformParameters)
,提示行为可以是new PlatformParameters(PromptBehavior.Auto)
两个版本中的提示行为自动表示:当用户尚未缓存时,将要求用户提供凭据。两个PromptBehavior.Auto
构造函数都允许您传递令牌缓存,这是您可以自己实现的。在内存,文件或数据库中缓存令牌(有关示例文件缓存实现,请参阅AcquireToken(string, string, Uri, PromptBehavior
)。
手动获取AccessToken
如果您真的想在不提示用户的情况下从代码传递用户凭据,那么总会有办法解决。在这种情况下,您必须按照OAuth2规范/ RFC6749中的规定实施this article。
巧合与否,我有一个名为Resource Owner Password Credentials grant的开源库实现了这个与AuthenticationContext
一起使用,但无论如何,如果你想走这条路,你可以深入研究这些代码,尤其是从oauth2-client-handler
开始。
使用访问令牌
获得访问令牌后,您可以继续this method上的示例,例如:
HttpClient
答案 1 :(得分:1)
如果有人仍在努力让它发挥作用。我们需要在应用程序的azure门户上载证书清单,然后使用相同的证书对客户端进行身份验证以获取访问令牌。有关详细信息,请参阅:https://blogs.msdn.microsoft.com/exchangedev/2015/01/21/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow/
答案 2 :(得分:0)
使用此 Microsoft Document 中的示例代码作为起点和这些库:
我能够在 Office 365 上成功验证并连接 Exchange。
public void Connect_OAuth()
{
var cca = ConfidentialClientApplicationBuilder
.Create ( ConfigurationManager.AppSettings[ "appId" ] )
.WithClientSecret( ConfigurationManager.AppSettings[ "clientSecret" ] )
.WithTenantId ( ConfigurationManager.AppSettings[ "tenantId" ] )
.Build();
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
AuthenticationResult authResult = null;
try
{
authResult = cca.AcquireTokenForClient( ewsScopes ).ExecuteAsync().Result;
}
catch( Exception ex )
{
Console.WriteLine( "Error: " + ex );
}
try
{
var ewsClient = new ExchangeService();
ewsClient.Url = new Uri( "https://outlook.office365.com/EWS/Exchange.asmx" );
ewsClient.Credentials = new OAuthCredentials( authResult.AccessToken );
ewsClient.ImpersonatedUserId = new ImpersonatedUserId( ConnectingIdType.SmtpAddress, "ccc@pppsystems.co.uk" );
ewsClient.HttpHeaders.Add( "X-AnchorMailbox", "ccc@pppsystems.co.uk" );
var folders = ewsClient.FindFolders( WellKnownFolderName.MsgFolderRoot, new FolderView( 10 ) );
foreach( var folder in folders )
{
Console.WriteLine( "" + folder.DisplayName );
}
}
catch( Exception ex )
{
Console.WriteLine( "Error: " + ex );
}
}
Microsoft 示例代码不起作用 - 对 AcquireTokenForClient
的异步调用从未返回。
通过在单独的 AcquireTokenForClient
try
块中调用 catch
来捕获一般 Exception
,删除 await
并使用 .Result
,现在有效 - 没有其他任何改变。
我意识到这不是最佳实践,但是,无论有没有调试器,原始代码中的异步调用都没有返回。
在 Azure 设置中:
希望这有助于人们避免数小时的沮丧。