簡體   English   中英

通過 EWS 托管 API 與 Exchange Online 交談時刷新訪問令牌

[英]Refresh access token when talking to Exchange Online via EWS Managed API

我正在編寫一個應用程序以使用 EWS Managed API 與 Exchange Online 通信,並使用 ADAL 庫通過 OAuth 2.0 驗證我的應用程序。

訪問令牌在 60 分鍾后過期。 之后我需要刷新訪問令牌。 目前,我正在 StreamSubscriptionConnection OnNotificationEvent 處理程序以及我的 OnDisconnect 事件處理程序中使用以下代碼刷新 OAuth 訪問令牌。

private void OnNotificationEventHandler(object sender, NotificationEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);

    // Do my work
}

我還在我的 OnDisconnect 事件處理程序中添加了相同的刷新訪問令牌代碼,因為 StreamSubscriptionConnection 最多只保持打開 30 分鍾。

private void OnDisconnectEventHandler(object sender, SubscriptionErrorEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);
    streamingSubscriptionConnection.Open();
}

這是我的訪問令牌代碼。

private async Task<string> GetOAuthAccessToken(PromptBehavior promptBehavior = PromptBehavior.Auto)
{
    var authenticationContext = new AuthenticationContext(myAadTenant);

    var authenticationResult = await authenticationContext.AcquireTokenAsync(exchangeOnlineServerName, myClientId, redirectUri, new PlatformParameters(promptBehavior));

    return authenticationResult.AccessToken;
}

即使認為上述方法“有效”,我也覺得這不是處理這種情況的最佳方法,因為我非常需要確保在與 EWS 通信時刷新我的訪問令牌。 如果我添加另一個事件處理程序並且忘記在事件處理程序中添加令牌刷新邏輯,如果我的訪問令牌過期但我需要在事件處理程序中調用 EWS,我可能會在處理該事件時收到 401。

上面的代碼被簡化了,每當我與 EWS 通信時我都可以嘗試捕獲,如果我得到 401,我刷新我的訪問令牌並重試,但這並沒有解決我上面提到的不便。

我認為應該有一種更簡單的方法來處理這個問題,但我還沒有找到正確的文檔。 這是我在開發時參考的材料。 https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/

我正在編寫一個應用程序以使用 EWS 托管 API 與 Exchange Online 通信,並使用 ADAL 庫通過 OAuth 2.0 對我的應用程序進行身份驗證。

訪問令牌在 60 分鍾后過期。 之后我需要刷新訪問令牌。 目前,我正在 StreamSubscriptionConnection OnNotificationEvent 處理程序以及 OnDisconnect 事件處理程序中使用以下代碼刷新 OAuth 訪問令牌。

private void OnNotificationEventHandler(object sender, NotificationEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);

    // Do my work
}

我還在 OnDisconnect 事件處理程序中添加了相同的刷新訪問令牌代碼,因為 StreamSubscriptionConnection 最多只保持打開 30 分鍾。

private void OnDisconnectEventHandler(object sender, SubscriptionErrorEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);
    streamingSubscriptionConnection.Open();
}

這是我的訪問令牌代碼。

private async Task<string> GetOAuthAccessToken(PromptBehavior promptBehavior = PromptBehavior.Auto)
{
    var authenticationContext = new AuthenticationContext(myAadTenant);

    var authenticationResult = await authenticationContext.AcquireTokenAsync(exchangeOnlineServerName, myClientId, redirectUri, new PlatformParameters(promptBehavior));

    return authenticationResult.AccessToken;
}

即使認為上述方法“有效”,我也覺得這不是處理這種情況的最佳方式,因為我幾乎需要確保在與 EWS 通信時刷新我的訪問令牌。 如果我添加另一個事件處理程序並且忘記在事件處理程序中添加令牌刷新邏輯,如果我的訪問令牌過期但我需要在事件處理程序中調用 EWS,我可能會在處理該事件時獲得 401。

上面的代碼被簡化了,每當我與 EWS 通信時,我都可以放置 try catch,如果我得到 401,我刷新我的訪問令牌並重試,但這並不能解決我上面提到的不便。

我認為應該有一種解決問題的簡便方法,但是我沒有找到正確的文檔。 這是我在進行開發時參考的材料。 https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/

我正在編寫一個應用程序以使用 EWS 托管 API 與 Exchange Online 通信,並使用 ADAL 庫通過 OAuth 2.0 對我的應用程序進行身份驗證。

訪問令牌在 60 分鍾后過期。 之后我需要刷新訪問令牌。 目前,我正在 StreamSubscriptionConnection OnNotificationEvent 處理程序以及 OnDisconnect 事件處理程序中使用以下代碼刷新 OAuth 訪問令牌。

private void OnNotificationEventHandler(object sender, NotificationEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);

    // Do my work
}

我還在 OnDisconnect 事件處理程序中添加了相同的刷新訪問令牌代碼,因為 StreamSubscriptionConnection 最多只保持打開 30 分鍾。

private void OnDisconnectEventHandler(object sender, SubscriptionErrorEventArgs args)
{
    exchangeService.Credentials = new OAuthCredentials(GetOAuthAccessToken().Result);
    streamingSubscriptionConnection.Open();
}

這是我的訪問令牌代碼。

private async Task<string> GetOAuthAccessToken(PromptBehavior promptBehavior = PromptBehavior.Auto)
{
    var authenticationContext = new AuthenticationContext(myAadTenant);

    var authenticationResult = await authenticationContext.AcquireTokenAsync(exchangeOnlineServerName, myClientId, redirectUri, new PlatformParameters(promptBehavior));

    return authenticationResult.AccessToken;
}

即使認為上述方法“有效”,我也覺得這不是處理這種情況的最佳方式,因為我幾乎需要確保在與 EWS 通信時刷新我的訪問令牌。 如果我添加另一個事件處理程序並且忘記在事件處理程序中添加令牌刷新邏輯,如果我的訪問令牌過期但我需要在事件處理程序中調用 EWS,我可能會在處理該事件時獲得 401。

上面的代碼被簡化了,每當我與 EWS 通信時,我都可以放置 try catch,如果我得到 401,我刷新我的訪問令牌並重試,但這並不能解決我上面提到的不便。

我認為應該有一種解決問題的簡便方法,但是我沒有找到正確的文檔。 這是我在進行開發時參考的材料。 https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/

我不得不在 netcore 應用程序中處理同樣的問題(使用官方 EWS 托管 API 客戶端的分支,它不會以任何方式觸及這方面)。 如 PaulG 的回答中所述,在完整請求之前主動執行.Bind會增加流量/延遲。 並且容易受到計時失敗的影響 - 綁定本身運行時令牌可能會超時,並且下一個請求無論如何都會失敗。

希望我的單點“重試 401”解決方案可以幫助某人。

private async Task Example() {
   var view = new FolderView(100);
   view.Traversal = FolderTraversal.Shallow;
   view.Offset = 0;
   await EWS(service => service.FindFolders((FolderId)WellKnownFolderName.MsgFolderRoot, view));
}

private async Task<T> EWS<T>(Func<ExchangeService, Task<T>> action)
{
    // just creates instance/returns one from cache and does some other unimportant stuff
    var service = await _getExchangeServiceAndBuildFolderIdCache();
    try
    {
        return await action(service);
    }
    // catch (ServiceRequestException e) when ((e.InnerException as System.Net.WebException)?.Response.StatusCode == StatusCode401Unauthorized)
    // ^^ is the more correct version. Would be. Except e.InnerException.Response is already disposed here.
    // Next best option is to just do substring match on message (and hope localization doesn't mess it up).
    catch (ServiceRequestException e) when (e.InnerException?.Message.Contains("(401)") ?? false)
    {
        // this tries AcquireTokenSilent first (which has internal cache for access token, and transparently falls back to refresh token if one is available). If silent fails, it also tries full AcquireTokenXxx call
        service.Credentials = await GetEWSCredentials();
        if (service.Credentials == null)
        {
            throw;
        }
        return await action(service);
    }
}

有一種微妙的方法可以檢查您的令牌是否已過期。 獲得令牌后

var authenticationResult = await authenticationContext.AcquireTokenAsync(exchangeOnlineServerName, myClientId, redirectUri, new PlatformParameters(promptBehavior));

您的 authenticationResult 對象具有ExpiresOn屬性,您可以檢查您的令牌是否已過期,然后刷新它。

就像是:

if (DateTime.Compare(authenticationResult.ExpiresOn.LocalDateTime, DateTimeOffset.Now.LocalDateTime) <= 0)
   {
     // Do your refresh token logic
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM