Asp.net-Core

ASP.NET Core 中的 AddOpenIdConnect 和刷新令牌

  • April 1, 2021

我已添加AddOpenIdConnectConfigureServices我的 ASP.NET Core 3.1 Razor 應用程序的方法中。在令牌過期之前它工作得很好,然後我從 IDP 收到 401 響應。

我看到了一個範例,該範例顯示了一種手動連接刷新令牌的方法。

但我很猶豫要不要這樣做。微軟的人似乎不太可能沒有考慮刷新令牌。

ASP.NET Core 3.1 是否有辦法讓刷新令牌自動更新訪問令牌?

這是我想出的。由於我找不到太多關於如何在 ASP.NET Core 中使用 cookie 刷新令牌的範例,所以我想我會在這裡發布。(我在問題中連結的那個有問題。)

這只是我試圖讓這個工作。它尚未在任何生產環境中使用。此程式碼在ConfigureServices方法中。

services.AddAuthentication(options =>
{
   options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
   options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
   options.Events = new CookieAuthenticationEvents
   {
       // After the auth cookie has been validated, this event is called.
       // In it we see if the access token is close to expiring.  If it is
       // then we use the refresh token to get a new access token and save them.
       // If the refresh token does not work for some reason then we redirect to 
       // the login screen.
       OnValidatePrincipal = async cookieCtx =>
       {
           var now = DateTimeOffset.UtcNow;
           var expiresAt = cookieCtx.Properties.GetTokenValue("expires_at");
           var accessTokenExpiration = DateTimeOffset.Parse(expiresAt);
           var timeRemaining = accessTokenExpiration.Subtract(now);
           // TODO: Get this from configuration with a fall back value.
           var refreshThresholdMinutes = 5;
           var refreshThreshold = TimeSpan.FromMinutes(refreshThresholdMinutes);

           if (timeRemaining < refreshThreshold)
           {
               var refreshToken = cookieCtx.Properties.GetTokenValue("refresh_token");
               // TODO: Get this HttpClient from a factory
               var response = await new HttpClient().RequestRefreshTokenAsync(new RefreshTokenRequest
               {
                   Address = tokenUrl,
                   ClientId = clientId,
                   ClientSecret = clientSecret,
                   RefreshToken = refreshToken
               });

               if (!response.IsError)
               {
                   var expiresInSeconds = response.ExpiresIn;
                   var updatedExpiresAt = DateTimeOffset.UtcNow.AddSeconds(expiresInSeconds);
                   cookieCtx.Properties.UpdateTokenValue("expires_at", updatedExpiresAt.ToString());
                   cookieCtx.Properties.UpdateTokenValue("access_token", response.AccessToken);
                   cookieCtx.Properties.UpdateTokenValue("refresh_token", response.RefreshToken);
                   
                   // Indicate to the cookie middleware that the cookie should be remade (since we have updated it)
                   cookieCtx.ShouldRenew = true;
               }
               else
               {
                   cookieCtx.RejectPrincipal();
                   await cookieCtx.HttpContext.SignOutAsync();
               }
           }
       }
   };
})
.AddOpenIdConnect(options =>
{
   options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
   
   options.Authority = oidcDiscoveryUrl;
   options.ClientId = clientId;
   options.ClientSecret = clientSecret;

   options.RequireHttpsMetadata = true;
   
   options.ResponseType = OidcConstants.ResponseTypes.Code;
   options.UsePkce = true;
   // This scope allows us to get roles in the service.
   options.Scope.Add("openid");
   options.Scope.Add("profile");
   options.Scope.Add("offline_access");

   // This aligns the life of the cookie with the life of the token.
   // Note this is not the actual expiration of the cookie as seen by the browser.
   // It is an internal value stored in "expires_at".
   options.UseTokenLifetime = false;
   options.SaveTokens = true;
});

這段程式碼有兩部分:

  1. AddOpenIdConnect:這部分程式碼為應用程序設置 OIDC。這裡的關鍵設置是:
  • SignInScheme:這讓 ASP.NET Core 知道您想要使用 cookie 來儲存您的身份驗證資訊。
    • UseTokenLifetime:據我了解,這會將 cookie 中的內部“expires_at”值設置為訪問令牌的生命週期。(不是實際的 cookie 過期,它停留在會話級別。)
    • SaveTokens:據我了解,這就是導致令牌保存在 cookie 中的原因。
  1. OnValidatePrincipal: 當 cookie 被驗證時,這個部分被呼叫。在本節中,我們檢查訪問令牌是否接近或過期。如果是,那麼它會被刷新並將更新的值儲存在 cookie 中。如果無法刷新令牌,則使用者將被重定向到登錄螢幕。

程式碼使用必須來自配置文件的這些值:

  • clientId:OAuth2 客戶端 ID。也稱為客戶端密鑰、消費者密鑰等。

  • clientSecret:OAuth2 客戶端密碼。也稱為消費者秘密等。

  • oidcDiscoveryUrl: 您的 IDP 的知名配置文件的 URL 的基本部分。如果您的 Well Known Configuration 文件位於,https://youridp.domain.com/oauth2/oidcdiscovery/.well-known/openid-configuration那麼該值將是https://youridp.domain.com/oauth2/oidcdiscovery.

  • tokenUrl: 指向您的 IDP 令牌端點的 URL。例如:https:/youridp.domain.com/oauth2/token

  • refreshThresholdMinutes:如果您等到訪問令牌即將到期,那麼您將面臨依賴訪問令牌的呼叫失敗的風險。(如果距離過期還有 5 毫秒,那麼它可能會過期,並且在您有機會刷新它之前呼叫失敗。)此設置是在過期前的分鐘數,您希望認為訪問令牌已準備好刷新。

  • 我是 ASP.NET Core 的新手。因此,我不能 100% 確定這些設置是否符合我的想法。這只是一些對我有用的程式碼,我想我會分享它。它可能適合您,也可能不適合您。

引用自:https://stackoverflow.com/questions/60858985