Код: Выделить всё
public class ManualCookieHttpClient : DelegatingHandler
{
private readonly Dictionary _cookies;
private readonly ILocalStorageService _localStorage;
private readonly IConfiguration _configuration;
private readonly IHttpClientFactory _httpClientFactory;
public ManualCookieHttpClient(ILocalStorageService localStorage, IConfiguration configuration, IHttpClientFactory httpClientFactory)
{
_cookies = new Dictionary(StringComparer.OrdinalIgnoreCase);
_localStorage = localStorage;
_configuration = configuration;
_httpClientFactory = httpClientFactory;
}
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AddBearerToken(request);
AddCookiesToRequest(request);
var response = await base.SendAsync(request, cancellationToken);
ProcessResponseCookies(response);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
return await HandleTokenRefresh(request, cancellationToken);
}
return response;
}
private void AddBearerToken(HttpRequestMessage request)
{
//Add Bearer Token...
}
private void AddCookiesToRequest(HttpRequestMessage request)
{
if (_cookies.Count == 0) return;
var cookieHeader = string.Join("; ", _cookies.Select(c => $"{c.Key}={c.Value}"));
request.Headers.Add("Cookie", cookieHeader);
}
private void ProcessResponseCookies(HttpResponseMessage response)
{
try
{
var requestUrl = response.RequestMessage?.RequestUri?.ToString();
Debug.WriteLine($"=== ProcessResponseCookies for: {requestUrl} ===");
Debug.WriteLine($"Response Status: {response.StatusCode}");
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 await base.SendAsync(originalRequest, cancellationToken);
}
}
else
{
throw new ApiException(
message: "Refreshing Token was not successful, Please login again.",
statusCode: 401,
response: await refreshResponse.Content.ReadAsStringAsync(),
headers: refreshResponse.Headers.ToDictionary(h => h.Key, h => h.Value.AsEnumerable()),
innerException: null
);
}
}
catch (ApiException)
{
throw;
}
catch (Exception ex)
{
throw new ApiException(
message: "Refresh Token Error",
statusCode: 401,
response: ex.Message,
headers: null,
innerException: ex
);
}
return await base.SendAsync(originalRequest, cancellationToken);
}
private string? GetUserNameFromToken()
{
//Get UserName From Token...
}
}
Код: Выделить всё
[HttpPost("refreshToken")]
public async Task RefreshToken([FromBody] RefreshTokenRequest request)
{
var authenticationResponse = await _authenticationService.RefreshTokenAsync(request.RefreshToken, request.UserName);
if (authenticationResponse == null)
return Unauthorized();
Response.Cookies.Append("RefreshToken", authenticationResponse.RefreshToken!, new CookieOptions
{
HttpOnly = true,
Secure = false,
SameSite = SameSiteMode.Lax,
Path = "/",
Expires = authenticationResponse.RefreshTokenExpirationDate,
});
return Ok(authenticationResponse);
}
< /code>
DelegatingHandlerКод: Выделить всё
services.AddTransient();
services.AddHttpClient(c =>
{
c.BaseAddress = new Uri(configuration.GetSection("ApiAddress").Value!);
})
.AddHttpMessageHandler()
.ConfigurePrimaryHttpMessageHandler(sp =>
{
return new HttpClientHandler
{
UseCookies = false,
AllowAutoRedirect = false
};
});
< /code>
I tried using SameSite = SameSiteMode.NoneПодробнее здесь: https://stackoverflow.com/questions/797 ... h-delegati