Refactor: Web Consolidation and Identity Stabilization #40
@@ -17,6 +17,8 @@ public record UserProfileDto
|
|||||||
/// Summary of the last read book.
|
/// Summary of the last read book.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LastReadBookDto? LastReadBook { get; init; }
|
public LastReadBookDto? LastReadBook { get; init; }
|
||||||
|
|
||||||
|
public string[] Roles { get; init; } = Array.Empty<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public record LastReadBookDto
|
public record LastReadBookDto
|
||||||
|
|||||||
@@ -48,7 +48,11 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
|||||||
Progress = e.Progress,
|
Progress = e.Progress,
|
||||||
LastChapter = e.LastChapter ?? "Rozpoczynanie...",
|
LastChapter = e.LastChapter ?? "Rozpoczynanie...",
|
||||||
LastChapterIndex = e.LastChapterIndex
|
LastChapterIndex = e.LastChapterIndex
|
||||||
}).FirstOrDefault()
|
}).FirstOrDefault(),
|
||||||
|
Roles = dbContext.UserRoles
|
||||||
|
.Where(ur => ur.UserId == u.Id)
|
||||||
|
.Join(dbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name!)
|
||||||
|
.ToArray()
|
||||||
})
|
})
|
||||||
.FirstOrDefaultAsync(cancellationToken);
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ public static class StorageKeys
|
|||||||
public const string RefreshToken = "nexus_refresh_token";
|
public const string RefreshToken = "nexus_refresh_token";
|
||||||
public const string UserEmail = "nexus_user_email";
|
public const string UserEmail = "nexus_user_email";
|
||||||
public const string UserTenant = "nexus_user_tenant";
|
public const string UserTenant = "nexus_user_tenant";
|
||||||
|
public const string UserRoles = "nexus_user_roles";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ public record UserProfile(
|
|||||||
Guid TenantId,
|
Guid TenantId,
|
||||||
SubscriptionPlanDto Plan,
|
SubscriptionPlanDto Plan,
|
||||||
int AverageQuizScore,
|
int AverageQuizScore,
|
||||||
LastReadBookDto? LastReadBook)
|
LastReadBookDto? LastReadBook,
|
||||||
|
string[] Roles)
|
||||||
{
|
{
|
||||||
// Helper properties for UI compatibility
|
// Helper properties for UI compatibility
|
||||||
public string CurrentPlan => Plan?.Name ?? PlanConstants.DefaultPlanName;
|
public string CurrentPlan => Plan?.Name ?? PlanConstants.DefaultPlanName;
|
||||||
@@ -104,11 +105,15 @@ public class IdentityService : IIdentityService
|
|||||||
var profile = profileResult.Value;
|
var profile = profileResult.Value;
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
||||||
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString());
|
|
||||||
|
var rolesStr = string.Join(",", profile.Roles ?? Array.Empty<string>());
|
||||||
|
await _storageService.SaveSecureString(StorageKeys.UserRoles, rolesStr);
|
||||||
|
|
||||||
|
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString(), rolesStr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(email, "unknown");
|
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(email, "unknown", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Ok();
|
return Result.Ok();
|
||||||
@@ -132,6 +137,7 @@ public class IdentityService : IIdentityService
|
|||||||
await _storageService.SaveSecureString(RefreshTokenKey, "");
|
await _storageService.SaveSecureString(RefreshTokenKey, "");
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, "");
|
await _storageService.SaveSecureString(StorageKeys.UserEmail, "");
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, "");
|
await _storageService.SaveSecureString(StorageKeys.UserTenant, "");
|
||||||
|
await _storageService.SaveSecureString(StorageKeys.UserRoles, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OnStateInvalidated != null) await OnStateInvalidated.Invoke();
|
if (OnStateInvalidated != null) await OnStateInvalidated.Invoke();
|
||||||
@@ -197,7 +203,11 @@ public class IdentityService : IIdentityService
|
|||||||
_cachedProfile = profile;
|
_cachedProfile = profile;
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
||||||
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString());
|
|
||||||
|
var rolesStr = string.Join(",", profile.Roles ?? Array.Empty<string>());
|
||||||
|
await _storageService.SaveSecureString(StorageKeys.UserRoles, rolesStr);
|
||||||
|
|
||||||
|
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString(), rolesStr);
|
||||||
}
|
}
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@@ -246,7 +256,11 @@ public class IdentityService : IIdentityService
|
|||||||
var profile = profileResult.Value;
|
var profile = profileResult.Value;
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
await _storageService.SaveSecureString(StorageKeys.UserEmail, profile.Email);
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
await _storageService.SaveSecureString(StorageKeys.UserTenant, profile.TenantId.ToString());
|
||||||
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString());
|
|
||||||
|
var rolesStr = string.Join(",", profile.Roles ?? Array.Empty<string>());
|
||||||
|
await _storageService.SaveSecureString(StorageKeys.UserRoles, rolesStr);
|
||||||
|
|
||||||
|
(_authStateProvider as NexusAuthenticationStateProvider)?.NotifyUserAuthentication(profile.Email, profile.TenantId.ToString(), rolesStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Ok();
|
return Result.Ok();
|
||||||
|
|||||||
@@ -38,10 +38,15 @@ public class NexusAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
{
|
{
|
||||||
var emailResult = await _storageService.GetSecureString(StorageKeys.UserEmail);
|
var emailResult = await _storageService.GetSecureString(StorageKeys.UserEmail);
|
||||||
var tenantIdResult = await _storageService.GetSecureString(StorageKeys.UserTenant);
|
var tenantIdResult = await _storageService.GetSecureString(StorageKeys.UserTenant);
|
||||||
|
var rolesResult = await _storageService.GetSecureString(StorageKeys.UserRoles);
|
||||||
|
|
||||||
if (emailResult.IsSuccess && !string.IsNullOrEmpty(emailResult.Value))
|
if (emailResult.IsSuccess && !string.IsNullOrEmpty(emailResult.Value))
|
||||||
{
|
{
|
||||||
_cachedState = CreateState(emailResult.Value, tenantIdResult.IsSuccess ? tenantIdResult.Value! : "unknown", "OpaqueBearer");
|
_cachedState = CreateState(
|
||||||
|
emailResult.Value,
|
||||||
|
tenantIdResult.IsSuccess ? tenantIdResult.Value! : "unknown",
|
||||||
|
"OpaqueBearer",
|
||||||
|
rolesResult.IsSuccess ? rolesResult.Value! : "");
|
||||||
return _cachedState;
|
return _cachedState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +56,12 @@ public class NexusAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
if (storedEmailResult.IsSuccess && !string.IsNullOrEmpty(storedEmailResult.Value))
|
if (storedEmailResult.IsSuccess && !string.IsNullOrEmpty(storedEmailResult.Value))
|
||||||
{
|
{
|
||||||
var tenantIdResult = await _storageService.GetSecureString(StorageKeys.UserTenant);
|
var tenantIdResult = await _storageService.GetSecureString(StorageKeys.UserTenant);
|
||||||
_cachedState = CreateState(storedEmailResult.Value, tenantIdResult.IsSuccess ? tenantIdResult.Value! : "unknown", "CookieAuth");
|
var rolesResult = await _storageService.GetSecureString(StorageKeys.UserRoles);
|
||||||
|
_cachedState = CreateState(
|
||||||
|
storedEmailResult.Value,
|
||||||
|
tenantIdResult.IsSuccess ? tenantIdResult.Value! : "unknown",
|
||||||
|
"CookieAuth",
|
||||||
|
rolesResult.IsSuccess ? rolesResult.Value! : "");
|
||||||
return _cachedState;
|
return _cachedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +77,7 @@ public class NexusAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthenticationState CreateState(string email, string tenantId, string authType)
|
private AuthenticationState CreateState(string email, string tenantId, string authType, string rolesStr = "")
|
||||||
{
|
{
|
||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
{
|
{
|
||||||
@@ -75,13 +85,23 @@ public class NexusAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
new Claim(ClaimTypes.Email, email),
|
new Claim(ClaimTypes.Email, email),
|
||||||
new Claim("TenantId", tenantId)
|
new Claim("TenantId", tenantId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(rolesStr))
|
||||||
|
{
|
||||||
|
var roles = rolesStr.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var role in roles)
|
||||||
|
{
|
||||||
|
claims.Add(new Claim(ClaimTypes.Role, role.Trim()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var identity = new ClaimsIdentity(claims, authType);
|
var identity = new ClaimsIdentity(claims, authType);
|
||||||
return new AuthenticationState(new ClaimsPrincipal(identity));
|
return new AuthenticationState(new ClaimsPrincipal(identity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotifyUserAuthentication(string email, string tenantId)
|
public void NotifyUserAuthentication(string email, string tenantId, string rolesStr = "")
|
||||||
{
|
{
|
||||||
_cachedState = CreateState(email, tenantId, "OpaqueBearer");
|
_cachedState = CreateState(email, tenantId, "OpaqueBearer", rolesStr);
|
||||||
NotifyAuthenticationStateChanged(Task.FromResult(_cachedState));
|
NotifyAuthenticationStateChanged(Task.FromResult(_cachedState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class ServerIdentityService : IIdentityService
|
|||||||
await _storageService.SaveSecureString(StorageKeys.RefreshToken, "");
|
await _storageService.SaveSecureString(StorageKeys.RefreshToken, "");
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserEmail, "");
|
await _storageService.SaveSecureString(StorageKeys.UserEmail, "");
|
||||||
await _storageService.SaveSecureString(StorageKeys.UserTenant, "");
|
await _storageService.SaveSecureString(StorageKeys.UserTenant, "");
|
||||||
|
await _storageService.SaveSecureString(StorageKeys.UserRoles, "");
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -88,7 +89,8 @@ public class ServerIdentityService : IIdentityService
|
|||||||
dto.TenantId,
|
dto.TenantId,
|
||||||
dto.Plan,
|
dto.Plan,
|
||||||
dto.AverageQuizScore,
|
dto.AverageQuizScore,
|
||||||
dto.LastReadBook
|
dto.LastReadBook,
|
||||||
|
dto.Roles
|
||||||
);
|
);
|
||||||
|
|
||||||
return Result.Ok(profile);
|
return Result.Ok(profile);
|
||||||
|
|||||||
Reference in New Issue
Block a user