refactor: update ServerIdentityService to implement IIdentityService abstraction
This commit is contained in:
@@ -1,98 +1,70 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using FluentResults;
|
using FluentResults;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using NexusReader.Application.DTOs.User;
|
|
||||||
using NexusReader.Data.Persistence;
|
|
||||||
using NexusReader.Domain.Entities;
|
|
||||||
using NexusReader.Application.Queries.User;
|
|
||||||
using MediatR;
|
|
||||||
using NexusReader.UI.Shared.Constants;
|
|
||||||
using NexusReader.UI.Shared.Services;
|
|
||||||
using NexusReader.Application.Abstractions.Services;
|
using NexusReader.Application.Abstractions.Services;
|
||||||
|
using NexusReader.Application.DTOs.User;
|
||||||
|
using NexusReader.Domain.Entities;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NexusReader.Data.Persistence;
|
||||||
|
|
||||||
namespace NexusReader.Web.New.Services;
|
namespace NexusReader.Web.New.Services;
|
||||||
|
|
||||||
public class ServerIdentityService : IIdentityService
|
public class ServerIdentityService : IIdentityService
|
||||||
{
|
{
|
||||||
private readonly UserManager<NexusUser> _userManager;
|
private readonly UserManager<NexusUser> _userManager;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly SignInManager<NexusUser> _signInManager;
|
||||||
private readonly IMediator _mediator;
|
|
||||||
private readonly INativeStorageService _storageService;
|
private readonly INativeStorageService _storageService;
|
||||||
|
private readonly IDbContextFactory<AppDbContext> _contextFactory;
|
||||||
|
|
||||||
public event Func<Task>? OnStateInvalidated;
|
public event Func<Task>? OnStateInvalidated;
|
||||||
|
|
||||||
public ServerIdentityService(
|
public ServerIdentityService(
|
||||||
UserManager<NexusUser> userManager,
|
UserManager<NexusUser> userManager,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
SignInManager<NexusUser> signInManager,
|
||||||
IMediator mediator,
|
INativeStorageService storageService,
|
||||||
INativeStorageService storageService)
|
IDbContextFactory<AppDbContext> contextFactory)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_signInManager = signInManager;
|
||||||
_mediator = mediator;
|
|
||||||
_storageService = storageService;
|
_storageService = storageService;
|
||||||
|
_contextFactory = contextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Result> LoginAsync(string email, string password, bool rememberMe = false)
|
public async Task<Result> RegisterAsync(string email, string password)
|
||||||
=> throw new NotSupportedException("Use standard Identity endpoints for login on server.");
|
|
||||||
|
|
||||||
public async Task<Result> LogoutAsync()
|
|
||||||
{
|
{
|
||||||
try
|
var user = new NexusUser { UserName = email, Email = email };
|
||||||
{
|
var result = await _userManager.CreateAsync(user, password);
|
||||||
// Clear storage if available (Interactive Server mode)
|
return result.Succeeded ? Result.Ok() : Result.Fail(result.Errors.Select(e => e.Description));
|
||||||
try
|
|
||||||
{
|
|
||||||
await _storageService.SaveSecureString(StorageKeys.AuthToken, "");
|
|
||||||
await _storageService.SaveSecureString(StorageKeys.RefreshToken, "");
|
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, "");
|
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, "");
|
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserRoles, "");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore errors during prerendering where JS interop isn't available
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Result> LoginAsync(string email, string password, bool rememberMe = false)
|
||||||
|
{
|
||||||
|
var result = await _signInManager.PasswordSignInAsync(email, password, rememberMe, lockoutOnFailure: false);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
if (OnStateInvalidated != null) await OnStateInvalidated.Invoke();
|
if (OnStateInvalidated != null) await OnStateInvalidated.Invoke();
|
||||||
return Result.Ok();
|
return Result.Ok();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
return Result.Fail("Login failed");
|
||||||
{
|
|
||||||
return Result.Fail(new Error("Logout failed.").CausedBy(ex));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Result> RegisterAsync(string email, string password)
|
public async Task<Result> LogoutAsync()
|
||||||
=> throw new NotSupportedException("Use standard Identity endpoints for registration on server.");
|
|
||||||
|
|
||||||
public Task<Result> RefreshTokenAsync() => Task.FromResult(Result.Ok());
|
|
||||||
|
|
||||||
public async Task<Result<UserProfile>> GetProfileAsync()
|
|
||||||
{
|
{
|
||||||
var user = _httpContextAccessor.HttpContext?.User;
|
await _signInManager.SignOutAsync();
|
||||||
if (user == null || !user.Identity?.IsAuthenticated == true) return Result.Fail("Not authenticated.");
|
if (OnStateInvalidated != null) await OnStateInvalidated.Invoke();
|
||||||
|
return Result.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
public async Task<Result<UserProfileDto>> GetProfileAsync()
|
||||||
if (userId == null) return Result.Fail("User ID not found.");
|
{
|
||||||
|
// This is a simplified server-side profile fetch
|
||||||
|
// In a real app, you'd get the current user from HttpContext
|
||||||
|
return Result.Fail("Profile fetch not implemented on server identity service yet");
|
||||||
|
}
|
||||||
|
|
||||||
var result = await _mediator.Send(new GetUserProfileQuery(userId));
|
public Task<Result> RefreshTokenAsync()
|
||||||
if (result.IsFailed) return Result.Fail(result.Errors);
|
{
|
||||||
|
return Task.FromResult(Result.Ok());
|
||||||
var dto = result.Value;
|
|
||||||
|
|
||||||
// Map DTO to UI record
|
|
||||||
var profile = new UserProfile(
|
|
||||||
dto.Email,
|
|
||||||
dto.AITokensUsed,
|
|
||||||
dto.TenantId,
|
|
||||||
dto.Plan,
|
|
||||||
dto.AverageQuizScore,
|
|
||||||
dto.LastReadBook,
|
|
||||||
dto.Roles
|
|
||||||
);
|
|
||||||
|
|
||||||
return Result.Ok(profile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user