- Introduced AuthService, IAuthApiClient, and AuthApiClient for managing authentication state and API calls (login, logout, session restore). - Added Login.razor and LoginLayout.razor for the login page, including styling and logic. - MainLayout.razor now checks authentication on load, restores sessions from sessionStorage, and redirects to /login if unauthenticated. Displays username and logout button when logged in. - Implemented JS interop (authStorage) for persisting authentication info in sessionStorage. - Registered AuthService, CookieContainer, and API clients in Program.cs to share cookies and support authentication. - Updated AppSettings and appsettings files to support separate ApiBaseUrl and DataApiBaseUrl. - Minor CSS improvements for username display in the top bar.
65 lines
2.3 KiB
C#
65 lines
2.3 KiB
C#
using System.Net;
|
|
|
|
namespace DbFirst.BlazorWebApp.Services;
|
|
|
|
public class AuthApiClient(HttpClient httpClient, AuthService authService, CookieContainer cookieContainer) : IAuthApiClient
|
|
{
|
|
private const string LoginEndpoint = "api/Auth/db-first/login";
|
|
private const string LogoutEndpoint = "api/Auth/logout";
|
|
private const string CheckEndpoint = "api/Auth/check";
|
|
|
|
public async Task<bool> LoginAsync(string username, string password, CancellationToken ct = default)
|
|
{
|
|
var content = new MultipartFormDataContent();
|
|
content.Add(new StringContent(username), "Username");
|
|
content.Add(new StringContent(password), "Password");
|
|
content.Add(new StringContent(string.Empty), "UserId");
|
|
|
|
var response = await httpClient.PostAsync(LoginEndpoint, content, ct);
|
|
if (!response.IsSuccessStatusCode)
|
|
return false;
|
|
|
|
var rawCookie = ExtractCookies();
|
|
authService.SetAuthenticated(username, rawCookie);
|
|
return true;
|
|
}
|
|
|
|
public async Task LogoutAsync(CancellationToken ct = default)
|
|
{
|
|
await httpClient.PostAsync(LogoutEndpoint, null, ct);
|
|
authService.SetUnauthenticated();
|
|
}
|
|
|
|
public async Task<bool> RestoreAsync(string username, string rawCookieHeader, CancellationToken ct = default)
|
|
{
|
|
RestoreCookies(rawCookieHeader);
|
|
var response = await httpClient.GetAsync(CheckEndpoint, ct);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
authService.SetAuthenticated(username, rawCookieHeader);
|
|
return true;
|
|
}
|
|
|
|
authService.SetUnauthenticated();
|
|
return false;
|
|
}
|
|
|
|
private string ExtractCookies()
|
|
{
|
|
if (httpClient.BaseAddress is null) return string.Empty;
|
|
var cookies = cookieContainer.GetCookies(httpClient.BaseAddress);
|
|
return string.Join("; ", cookies.Cast<Cookie>().Select(c => $"{c.Name}={c.Value}"));
|
|
}
|
|
|
|
private void RestoreCookies(string rawCookieHeader)
|
|
{
|
|
if (httpClient.BaseAddress is null) return;
|
|
foreach (var part in rawCookieHeader.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
var eqIdx = part.IndexOf('=');
|
|
if (eqIdx > 0)
|
|
cookieContainer.Add(httpClient.BaseAddress, new Cookie(part[..eqIdx].Trim(), part[(eqIdx + 1)..].Trim()));
|
|
}
|
|
}
|
|
}
|