Как настроить перенаправление на refresh-token при получении ошибки AuthenticationFailed в asp.net core web api?

Как настроить перенаправление на `refresh-token` endpoint при истечении срока жизни `access token` в проекте `asp.net core web api`, используя конфигурацию аутентификации с `AddJwtBearer`? В данный момент, событие `OnAuthenticationFailed` срабатывает при получении `HttpStatusCode401`, но `context.Response.Redirect()` не выполняет перенаправление.
  • 26 марта 2024 г. 16:59
Ответы на вопрос 3
Для настройки перенаправления на `refresh-token` endpoint при получении ошибки `AuthenticationFailed` в `asp.net core web api`, вы можете использовать следующий подход:

1. Во-первых, вам нужно добавить обработчик события `OnAuthenticationFailed` в методе `ConfigureServices` вашего `Startup` класса:

```c#
services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = Configuration["Jwt:Issuer"],
        ValidAudience = Configuration["Jwt:Issuer"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])),
        ClockSkew = TimeSpan.Zero
    };

    options.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
            {
                // Ваш код для перенаправления на refresh-token endpoint
                context.Response.Redirect("/api/refresh-token");
            }
            return Task.CompletedTask;
        }
    };
});
```

2. Затем вам нужно добавить контроллер для `refresh-token` endpoint, где клиент может обменять `refresh token` на новый `access token`. Например:

```c#
[HttpPost("refresh-token")]
public async Task<IActionResult> RefreshToken()
{
    // Ваш код для обмена refresh token на новый access token
    return Ok();
}
```

3. Наконец, проверьте, что ваши `access token` и `refresh token` настроены и используются правильно в вашем проекте.

Теперь, при истечении срока действия `access token`, при получении ошибки `AuthenticationFailed` произойдет перенаправление на `refresh-token` endpoint, где клиент сможет получить новый `access token`.
Решил. Как это всё делается? Внутрь onAuthenticationFailed вставляем этот код: 
if (context.Exception?.GetType() == typeof(SecurityTokenExpiredException))
{
    IJwtService jwtService = context.HttpContext.RequestServices.GetService<IJwtService>();

    if (context.Request.Cookies.TryGetValue("refresh-token", out string refreshToken))
    {
        Result<ClaimsPrincipal> principalResult = jwtService.ValidateAndDecodeToken(refreshToken);
        if (!principalResult.IsSuccess || principalResult.Value == null)
        {
            return Task.CompletedTask;
        }

        Result<string> renewAccessTokenResult = jwtService.Encode(principalResult.Value);
        if (!renewAccessTokenResult.IsSuccess && renewAccessTokenResult.ValidationErrors.Any())
        {
            return Task.CompletedTask;
        }

        context.Response.Cookies.Append("access-token", renewAccessTokenResult.Value);
        context.Response.StatusCode = 200;
        context.HttpContext.User = principalResult.Value;
        context.Principal = principalResult.Value;
        context.Success();
    }
}
return Task.CompletedTask;


Т.е.. вызывает сервис, берём refresh token и из него извлекаем ClaimPrincipal , далее на его основе делаем access token из того же сервиса и обрабатываем запрос, что бы он возвращал нужный статус. Как говорил Andrei SunnyPh , это допустимая практика (Спасибо)
Клиент сам должен следить за временем жизни токена и сам делать рефреш.
Похожие вопросы