СМ. Ниже для кода, который решил эту проблему
Я пытаюсь найти лучший и наиболее эффективный способ обработки токена обновления, срок действия которого истек в ASP.NET Core 2.1.
Позвольте мне объяснить немного больше.
Я использую OAUTH2 и OIDC для запроса потоков разрешения кода авторизации (или гибридного потока с OIDC). Этот тип потока / предоставления дает мне доступ к AccessToken и RefreshToken (Код авторизации также, но это не для этого вопроса).
Токен доступа и токен обновления хранятся в ядре ASP.NET и могут быть получены с помощью HttpContext.GetTokenAsync("access_token");
и HttpContext.GetTokenAsync("refresh_token");
соответственно.
Я могу обновить access_token
без проблем. Эта проблема вступает в игру, когда срок действия refresh_token
истек, отозван или недействителен каким-либо образом.
Правильный поток будет состоять в том, чтобы пользователь снова вошел в систему и снова вернулся через весь поток аутентификации. Затем приложение получает новый набор возвращаемых токенов.
Мой вопрос заключается в том, как добиться этого наилучшим и наиболее правильным методом. Я решил написать пользовательское промежуточное ПО, которое пытается обновить access_token
, если срок его действия истек. Затем промежуточное ПО устанавливает новый токен в AuthenticationProperties
для HttpContext, чтобы его можно было использовать любыми вызовами позже по каналу.
Если по какой-либо причине не удается обновить токен, мне нужно снова вызвать ChallengeAsync. Я звоню ChallengeAsync из промежуточного программного обеспечения.
Здесь я сталкиваюсь с интересным поведением. В большинстве случаев это работает, однако иногда я получаю 500 ошибок без полезной информации о том, что не работает. Похоже, что промежуточное ПО испытывает проблемы с попыткой вызова ChallengeAsync из промежуточного ПО, и, возможно, другое промежуточное ПО также пытается получить доступ к контексту.
Я не совсем уверен, что происходит. Я не совсем уверен, если это правильное место, чтобы поставить эту логику или нет. Может быть, я не должен иметь это в промежуточном программном обеспечении, может быть, где-то еще Возможно, Полли для HttpClient - лучшее место.
Я открыт для любых идей.
Спасибо за любую помощь, которую вы можете предоставить.
Code Solution, который работал для меня
Спасибо Mickaël Derriey за помощь и руководство (не забудьте посмотреть его ответ для получения дополнительной информации о контексте этого решения) Это решение, которое я придумал, и оно работает для я:
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
//check to see if user is authenticated first
if (context.Principal.Identity.IsAuthenticated)
{
//get the users tokens
var tokens = context.Properties.GetTokens();
var refreshToken = tokens.FirstOrDefault(t => t.Name == "refresh_token");
var accessToken = tokens.FirstOrDefault(t => t.Name == "access_token");
var exp = tokens.FirstOrDefault(t => t.Name == "expires_at");
var expires = DateTime.Parse(exp.Value);
//check to see if the token has expired
if (expires < DateTime.Now)
{
//token is expired, let's attempt to renew
var tokenEndpoint = "https://token.endpoint.server";
var tokenClient = new TokenClient(tokenEndpoint, clientId, clientSecret);
var tokenResponse = tokenClient.RequestRefreshTokenAsync(refreshToken.Value).Result;
//check for error while renewing - any error will trigger a new login.
if (tokenResponse.IsError)
{
//reject Principal
context.RejectPrincipal();
return Task.CompletedTask;
}
//set new token values
refreshToken.Value = tokenResponse.RefreshToken;
accessToken.Value = tokenResponse.AccessToken;
//set new expiration date
var newExpires = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);
exp.Value = newExpires.ToString("o", CultureInfo.InvariantCulture);
//set tokens in auth properties
context.Properties.StoreTokens(tokens);
//trigger context to renew cookie with new token values
context.ShouldRenew = true;
return Task.CompletedTask;
}
}
return Task.CompletedTask;
}
};