Initial commit
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
/// <summary>Stores OAuth tokens in ProtectedSessionStorage (browser-side, encrypted).
|
||||
/// Nothing written to server disk.</summary>
|
||||
public interface ISessionCredentialStore
|
||||
{
|
||||
Task<SessionTokens?> GetAsync();
|
||||
Task SetAsync(SessionTokens tokens);
|
||||
Task UpdateRefreshTokenAsync(string newRefreshToken);
|
||||
Task ClearAsync();
|
||||
Task<bool> HasCredentialsAsync();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
/// <summary>Scoped per Blazor circuit. Set once on circuit init from auth state.</summary>
|
||||
public interface IUserContextAccessor
|
||||
{
|
||||
string Email { get; }
|
||||
string DisplayName { get; }
|
||||
UserRole Role { get; }
|
||||
bool IsAuthenticated { get; }
|
||||
|
||||
event Action? Initialized;
|
||||
|
||||
void Initialize(AppUser user);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
/// <summary>
|
||||
/// Scoped per Blazor circuit. Holds the active tenant profile for the current user.
|
||||
/// All feature pages read the profile from here instead of asking the user per-request.
|
||||
/// </summary>
|
||||
public interface IUserSessionService
|
||||
{
|
||||
TenantProfile? CurrentProfile { get; }
|
||||
bool HasProfile { get; }
|
||||
AppSettings Settings { get; }
|
||||
|
||||
void SetProfile(TenantProfile profile);
|
||||
Task ClearSessionAsync();
|
||||
void UpdateSettings(AppSettings settings);
|
||||
event Action? ProfileChanged;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
public class SessionCredentialStore : ISessionCredentialStore
|
||||
{
|
||||
private const string Key = "sp-session-tokens";
|
||||
private readonly ProtectedSessionStorage _storage;
|
||||
|
||||
public SessionCredentialStore(ProtectedSessionStorage storage) { _storage = storage; }
|
||||
|
||||
public async Task<SessionTokens?> GetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _storage.GetAsync<SessionTokens>(Key);
|
||||
return result.Success ? result.Value : null;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public async Task SetAsync(SessionTokens tokens) =>
|
||||
await _storage.SetAsync(Key, tokens);
|
||||
|
||||
public async Task UpdateRefreshTokenAsync(string newRefreshToken)
|
||||
{
|
||||
var tokens = await GetAsync();
|
||||
if (tokens is null) return;
|
||||
tokens.RefreshToken = newRefreshToken;
|
||||
await _storage.SetAsync(Key, tokens);
|
||||
}
|
||||
|
||||
public async Task ClearAsync() =>
|
||||
await _storage.DeleteAsync(Key);
|
||||
|
||||
public async Task<bool> HasCredentialsAsync()
|
||||
{
|
||||
var tokens = await GetAsync();
|
||||
return tokens is not null && !string.IsNullOrEmpty(tokens.RefreshToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
public class UserContextAccessor : IUserContextAccessor
|
||||
{
|
||||
private AppUser? _user;
|
||||
|
||||
public string Email => _user?.Email ?? string.Empty;
|
||||
public string DisplayName => _user?.DisplayName ?? string.Empty;
|
||||
public UserRole Role => _user?.Role ?? UserRole.TechN0;
|
||||
public bool IsAuthenticated => _user is not null;
|
||||
|
||||
public event Action? Initialized;
|
||||
|
||||
public void Initialize(AppUser user)
|
||||
{
|
||||
_user = user;
|
||||
Initialized?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using SharepointToolbox.Web.Core.Models;
|
||||
using SharepointToolbox.Web.Infrastructure.Persistence;
|
||||
|
||||
namespace SharepointToolbox.Web.Services.Session;
|
||||
|
||||
public class UserSessionService : IUserSessionService
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly SettingsRepository _settingsRepo;
|
||||
|
||||
private TenantProfile? _currentProfile;
|
||||
private AppSettings _settings = new();
|
||||
|
||||
public TenantProfile? CurrentProfile => _currentProfile;
|
||||
public bool HasProfile => _currentProfile is not null;
|
||||
public AppSettings Settings => _settings;
|
||||
|
||||
public event Action? ProfileChanged;
|
||||
|
||||
public UserSessionService(ISessionManager sessionManager, SettingsRepository settingsRepo)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
_settingsRepo = settingsRepo;
|
||||
_ = LoadSettingsAsync();
|
||||
}
|
||||
|
||||
public void SetProfile(TenantProfile profile)
|
||||
{
|
||||
_currentProfile = profile;
|
||||
ProfileChanged?.Invoke();
|
||||
}
|
||||
|
||||
public async Task ClearSessionAsync()
|
||||
{
|
||||
if (_currentProfile is not null)
|
||||
await _sessionManager.ClearSessionAsync(_currentProfile.TenantUrl);
|
||||
_currentProfile = null;
|
||||
ProfileChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void UpdateSettings(AppSettings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
_ = _settingsRepo.SaveAsync(settings);
|
||||
}
|
||||
|
||||
private async Task LoadSettingsAsync()
|
||||
{
|
||||
try { _settings = await _settingsRepo.LoadAsync(); }
|
||||
catch { /* use defaults */ }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user