AddOpenIdConnect и Refre sh токенов в ASP. NET Core - PullRequest
0 голосов
/ 26 марта 2020

Я добавил AddOpenIdConnect в метод ConfigureServices моего приложения ASP. NET Core 3.1 Razor. Он прекрасно работает, пока токен не истекает, тогда я получаю 401 ответ от моего IDP.

Я видел пример , который показывает способ подключения refre sh токенов вручную.

Но я не решаюсь это сделать. Очень маловероятно, что люди в Microsoft не думали о refre sh токенах.

Имеет ли ASP. NET Core 3.1 способ автоматически обновлять sh токенов токен доступа?

Ответы [ 2 ]

2 голосов
/ 28 марта 2020

Вот что я придумал. Поскольку я не могу найти много примеров того, как сделать refre sh token в 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 = true;
    options.SaveTokens = true;
});

Этот код состоит из двух частей:

  1. AddOpenIdConnect: эта часть кода устанавливает OID C для приложение. Основные настройки здесь:
    • SignInScheme: это позволяет ASP. NET Core знать, что вы хотите использовать куки для хранения вашей информации аутентификации.
    • *UseTokenLifetime: Как я поймите, это устанавливает внутреннее значение "expires_at" в cook ie как срок жизни токена доступа. (Не фактический срок действия повара ie, который остается на уровне сеанса.)
    • *SaveTokens: Насколько я понимаю, именно из-за этого токены сохраняются в поваре ie.
  2. OnValidatePrincipal: этот раздел вызывается, когда повар ie подтвержден. В этом разделе мы проверяем, близок ли или истек срок действия токена доступа. Если это так, то он обновляется и обновленные значения сохраняются в файле cook ie. Если токен не может быть обновлен, то пользователь перенаправляется на экран входа в систему.

Код использует следующие значения, которые должны поступить из вашего файла конфигурации:

  • clientId : Идентификатор клиента OAuth2. Также называется ключом клиента, ключом потребителя и т. Д. c.
  • clientSecret: OAuth2 Client Secret. Также называется Consumer Secret и т. Д. c.
  • oidcDiscoveryUrl: базовая часть URL-адреса для хорошо известного документа конфигурации вашего IDP. Если документ общеизвестной конфигурации имеет значение https://youridp.domain.com/oauth2/oidcdiscovery/.well-known/openid-configuration, тогда это значение будет https://youridp.domain.com/oauth2/oidcdiscovery.
  • tokenUrl: URL-адрес конечной точки токена вашего IDP. Например: https:/youridp.domain.com/oauth2/token
  • refreshThresholdMinutes: если вы подождете, пока токен доступа очень близок к истечению срока действия, вы рискуете прервать вызовы, основанные на маркере доступа. (Если срок действия истекает через 5 миллисекунд, то он может истечь и завершиться ошибкой вызова, прежде чем вы получите возможность обновить sh.) Этот параметр задает количество минут до истечения срока действия, которое вы хотите считать токеном доступа готовым к

* Я новичок в ASP. NET Core. Поэтому я не уверен на 100%, что эти настройки делают то, что я думаю. Это всего лишь кусок кода, который работает для меня, и я подумал, что поделюсь им. Это может или не может работать для вас.

0 голосов
/ 26 марта 2020

AddOpenIdConnect используется для настройки обработчика, который выполняет протокол OpenID Connect для получения токенов от вашего поставщика удостоверений. Но он не знает, где вы хотите сохранить токены. Это может быть любое из следующего:

  • Cook ie
  • Memory
  • База данных

Вы можете хранить токены в Повар ie затем проверяет время истечения токена и обновляет sh токены, перехватывая событие проверки повара ie (как показано в примере).

Но AddOpenIdConnect не имеет логика c для управления тем, где пользователь хочет хранить токены, и автоматическая реализация токена refre sh.

Вы также можете попытаться обернуть промежуточное программное обеспечение как ADAL.NET/MSAL.NET, чтобы обеспечить функции кэширования, и затем вы можете получать / обновлять sh токены в автоматическом режиме.

...