149 lines
5.2 KiB
C#
149 lines
5.2 KiB
C#
using System.Net.Http.Json;
|
|
using NexusReader.Application.Abstractions.Services;
|
|
|
|
namespace NexusReader.UI.Shared.Services;
|
|
|
|
public interface IIdentityService
|
|
{
|
|
Task<bool> RegisterAsync(string email, string password);
|
|
Task<bool> LoginAsync(string email, string password, bool rememberMe = false);
|
|
Task LogoutAsync();
|
|
Task<UserProfile?> GetProfileAsync();
|
|
Task<bool> RefreshTokenAsync();
|
|
}
|
|
|
|
public record UserProfile(
|
|
string Email,
|
|
int AITokenLimit,
|
|
int AITokensUsed,
|
|
string CurrentPlan,
|
|
Guid TenantId,
|
|
int AverageQuizScore,
|
|
string LastReadBookTitle);
|
|
|
|
public class IdentityService : IIdentityService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly INativeStorageService _storageService;
|
|
private readonly NexusAuthenticationStateProvider _authStateProvider;
|
|
private const string TokenKey = "nexus_auth_token";
|
|
private const string RefreshTokenKey = "nexus_refresh_token";
|
|
|
|
public IdentityService(
|
|
HttpClient httpClient,
|
|
INativeStorageService storageService,
|
|
NexusAuthenticationStateProvider authStateProvider)
|
|
{
|
|
_httpClient = httpClient;
|
|
_storageService = storageService;
|
|
_authStateProvider = authStateProvider;
|
|
}
|
|
|
|
public async Task<bool> RegisterAsync(string email, string password)
|
|
{
|
|
var response = await _httpClient.PostAsJsonAsync("identity/register", new { email, password });
|
|
return response.IsSuccessStatusCode;
|
|
}
|
|
|
|
public async Task<bool> LoginAsync(string email, string password, bool rememberMe = false)
|
|
{
|
|
var response = await _httpClient.PostAsJsonAsync("identity/login", new { email, password });
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<LoginResponse>();
|
|
if (result != null && !string.IsNullOrEmpty(result.AccessToken))
|
|
{
|
|
await _storageService.SaveSecureString(TokenKey, result.AccessToken);
|
|
if (!string.IsNullOrEmpty(result.RefreshToken))
|
|
{
|
|
await _storageService.SaveSecureString(RefreshTokenKey, result.RefreshToken);
|
|
}
|
|
|
|
// Option A: Fetch profile to get claims
|
|
var profile = await GetProfileAsync();
|
|
if (profile != null)
|
|
{
|
|
await _storageService.SaveSecureString("nexus_user_email", profile.Email);
|
|
await _storageService.SaveSecureString("nexus_user_tenant", profile.TenantId.ToString());
|
|
|
|
_authStateProvider.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString());
|
|
}
|
|
else
|
|
{
|
|
// Fallback if profile fetch fails
|
|
_authStateProvider.NotifyUserAuthentication(email, "unknown");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task LogoutAsync()
|
|
{
|
|
_storageService.RemoveSecure(TokenKey);
|
|
_storageService.RemoveSecure(RefreshTokenKey);
|
|
_storageService.RemoveSecure("nexus_user_email");
|
|
_storageService.RemoveSecure("nexus_user_tenant");
|
|
_authStateProvider.NotifyUserLogout();
|
|
}
|
|
|
|
public async Task<UserProfile?> GetProfileAsync()
|
|
{
|
|
try
|
|
{
|
|
return await _httpClient.GetFromJsonAsync<UserProfile>("identity/profile");
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<bool> RefreshTokenAsync()
|
|
{
|
|
var result = await _storageService.GetSecureString(RefreshTokenKey);
|
|
var refreshToken = result.IsSuccess ? result.Value : null;
|
|
|
|
if (string.IsNullOrEmpty(refreshToken)) return false;
|
|
|
|
var response = await _httpClient.PostAsJsonAsync("identity/refresh", new { refreshToken });
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var loginResult = await response.Content.ReadFromJsonAsync<LoginResponse>();
|
|
if (loginResult != null && !string.IsNullOrEmpty(loginResult.AccessToken))
|
|
{
|
|
await _storageService.SaveSecureString(TokenKey, loginResult.AccessToken);
|
|
if (!string.IsNullOrEmpty(loginResult.RefreshToken))
|
|
{
|
|
await _storageService.SaveSecureString(RefreshTokenKey, loginResult.RefreshToken);
|
|
}
|
|
|
|
var profile = await GetProfileAsync();
|
|
if (profile != null)
|
|
{
|
|
await _storageService.SaveSecureString("nexus_user_email", profile.Email);
|
|
await _storageService.SaveSecureString("nexus_user_tenant", profile.TenantId.ToString());
|
|
_authStateProvider.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private class LoginResponse
|
|
{
|
|
public string TokenType { get; set; } = string.Empty;
|
|
public string AccessToken { get; set; } = string.Empty;
|
|
public int ExpiresIn { get; set; }
|
|
public string RefreshToken { get; set; } = string.Empty;
|
|
}
|
|
}
|