Files
radius/radiuscontroller/Services/AdminAuthService.cs
Tygozwolle 09de033d70
Build and Push Docker Image to Gitea Container Registry / build-and-push (push) Successful in 1m24s
Build and Push Docker Image to Gitea Container Registry / build-and-push (pull_request) Successful in 1m19s
create user
2026-07-24 11:56:40 +02:00

113 lines
3.3 KiB
C#

using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using Microsoft.EntityFrameworkCore;
using radiuscontroller.Data;
using radiuscontroller.Models;
namespace radiuscontroller.Services;
public class AdminAuthService
{
private readonly RadiusDbContext _db;
private readonly ProtectedSessionStorage _sessionStorage;
private const string SessionKey = "AdminUsername";
public string? CurrentAdminUsername { get; private set; }
public bool IsAuthenticated => !string.IsNullOrEmpty(CurrentAdminUsername);
public event Action? OnAuthStateChanged;
public AdminAuthService(RadiusDbContext db, ProtectedSessionStorage sessionStorage)
{
_db = db;
_sessionStorage = sessionStorage;
}
public async Task InitializeAsync()
{
try
{
var result = await _sessionStorage.GetAsync<string>(SessionKey);
if (result.Success && !string.IsNullOrEmpty(result.Value))
{
CurrentAdminUsername = result.Value;
NotifyStateChanged();
}
}
catch
{
// Session storage might fail during prerendering or early socket connection
CurrentAdminUsername = null;
}
}
public async Task<bool> HasAnyAdminAsync()
{
return await _db.AdminUsers.AnyAsync();
}
public async Task<bool> RegisterInitialAdminAsync(string username, string password)
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return false;
// Ensure first-time setup is only allowed if no admin users exist
if (await _db.AdminUsers.AnyAsync())
return false;
string cleanUsername = username.Trim().ToLowerInvariant();
string hash = BCrypt.Net.BCrypt.HashPassword(password.Trim());
var admin = new AdminUser
{
Username = cleanUsername,
PasswordHash = hash,
CreatedAt = DateTime.UtcNow
};
_db.AdminUsers.Add(admin);
await _db.SaveChangesAsync();
CurrentAdminUsername = admin.Username;
await _sessionStorage.SetAsync(SessionKey, admin.Username);
NotifyStateChanged();
return true;
}
public async Task<bool> LoginAsync(string username, string password)
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return false;
var admin = await _db.AdminUsers.FirstOrDefaultAsync(u => u.Username == username.Trim().ToLowerInvariant());
if (admin == null)
return false;
bool isValid = BCrypt.Net.BCrypt.Verify(password, admin.PasswordHash);
if (isValid)
{
CurrentAdminUsername = admin.Username;
await _sessionStorage.SetAsync(SessionKey, admin.Username);
NotifyStateChanged();
return true;
}
return false;
}
public async Task LogoutAsync()
{
CurrentAdminUsername = null;
try
{
await _sessionStorage.DeleteAsync(SessionKey);
}
catch
{
// Ignore storage errors during logout
}
NotifyStateChanged();
}
private void NotifyStateChanged() => OnAuthStateChanged?.Invoke();
}