У меня есть проект .NET с двумя слоями: слой API и слой пользовательского интерфейса, оба в одном решении. Уровень пользовательского интерфейса построен с помощью MVC, где контроллеры вызовут службы, а службы используют httpclient, сгенерированные NSWAG Studio для вызова конечных точек API. Он вручную читает файлы cookie из заголовков ответов и хранит их в словаре. Логика состоит в том, что если токен доступа JWT истекает, и я получаю 401 несанкционированный ответ , обработчик извлекает токен обновления из файлов cookie и отправляет его в обновленный API. Это отлично работает около двух минут, но после этого сервер перестает отправлять заголовки Set-cookie в ответах API, и их значения становятся нулевыми.
Я попытался использовать samesite = samesitemode.none , но это не решило проблему.
Помимо этого, я понятия не имею, как отлаживать и найти основную причину! Из -за этого я сейчас вручную обрабатываю файлы cookie в моем делегировании и код .
У меня есть проект .NET с двумя слоями: слой API и слой пользовательского интерфейса, оба в одном решении. Уровень пользовательского интерфейса построен с помощью MVC, где контроллеры вызовут службы, а службы используют httpclient, сгенерированные NSWAG Studio для вызова конечных точек API. Он вручную читает файлы cookie из заголовков ответов и хранит их в словаре. Логика состоит в том, что если токен доступа JWT истекает, и я получаю 401 несанкционированный ответ , обработчик извлекает токен обновления из файлов cookie и отправляет его в обновленный API. Это отлично работает около двух минут, но после этого сервер перестает отправлять заголовки Set-cookie в ответах API, и их значения становятся нулевыми.[code]public class ManualCookieHttpClient : DelegatingHandler { private readonly Dictionary _cookies; private readonly ILocalStorageService _localStorage; private readonly IConfiguration _configuration; private readonly IHttpClientFactory _httpClientFactory;
if (response.Headers.TryGetValues("Set-Cookie", out var setCookieHeaders)) { foreach(var cookie in setCookieHeaders) { Console.WriteLine(cookie); }
foreach (var setCookieHeader in setCookieHeaders) { var cookieParts = setCookieHeader.Split(';')[0].Split('='); if (cookieParts.Length == 2) { var name = cookieParts[0].Trim(); var value = cookieParts[1].Trim();
if (string.IsNullOrEmpty(value)) continue;
_cookies[name] = value; } } }
if (_cookies.ContainsKey("RefreshToken")) { var currentToken = _cookies["RefreshToken"]; } else { Console.WriteLine("there is no refreshToken in headers cookies"); } } catch (Exception e) { Debug.WriteLine($"Exception in ProcessResponseCookies: {e.Message}"); } }
private async Task HandleTokenRefresh(HttpRequestMessage originalRequest, CancellationToken cancellationToken) { try { var userName = GetUserNameFromToken(); if (string.IsNullOrEmpty(userName)) { throw new ApiException( message: "User is not authenticated", statusCode: 401, response: "User not authenticated", headers: null, innerException: null ); }
var refreshToken = _cookies.ContainsKey("refreshToken") ? _cookies["refreshToken"] : null;
if (string.IsNullOrEmpty(refreshToken)) { throw new ApiException( message: "Refresh Token does not exist", statusCode: 401, response: "Refresh token not found", headers: null, innerException: null ); }
var apiAddress = _configuration["ApiAddress"];
var client = _httpClientFactory.CreateClient("RefreshClient"); client.BaseAddress = new Uri(apiAddress!);
var refreshRequest = new HttpRequestMessage(HttpMethod.Post, "api/Account/refreshToken"); AddCookiesToRequest(refreshRequest);
var refreshTokenRequest = new RefreshTokenRequest { UserName = userName, RefreshToken = refreshToken }; refreshRequest.Content = JsonContent.Create(refreshTokenRequest);
var refreshResponse = await client.SendAsync(refreshRequest, cancellationToken);
if (refreshResponse.IsSuccessStatusCode) { string newRefreshToken = null!; if (refreshResponse.Headers.TryGetValues("Set-Cookie", out var setCookieHeaders)) { foreach (var setCookieHeader in setCookieHeaders) { if (setCookieHeader.StartsWith("refreshToken=")) { var cookieParts = setCookieHeader.Split(';')[0].Split('='); if (cookieParts.Length == 2) { newRefreshToken = cookieParts[1].Trim(); _cookies["refreshToken"] = newRefreshToken; } } } }
ProcessResponseCookies(refreshResponse);
var authResponse = await refreshResponse.Content.ReadFromJsonAsync();
if (!string.IsNullOrWhiteSpace(authResponse?.Token)) { _localStorage.SetStorageValue("token", authResponse.Token);
AddCookiesToRequest(originalRequest);
originalRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResponse.Token);
return Ok(authenticationResponse); } [/code] Настройки делегирующих рук в программе.[code] services.AddTransient();
services.AddHttpClient(c => { c.BaseAddress = new Uri(configuration.GetSection("ApiAddress").Value!); }) .AddHttpMessageHandler() .ConfigurePrimaryHttpMessageHandler(sp => { return new HttpClientHandler { UseCookies = false, AllowAutoRedirect = false }; }); [/code] Я попытался использовать samesite = samesitemode.none , но это не решило проблему. Помимо этого, я понятия не имею, как отлаживать и найти основную причину! Из -за этого я сейчас вручную обрабатываю файлы cookie в моем делегировании и код .