Files
timetracker/Data/AuthService.cs
T
2026-06-07 23:36:45 +02:00

76 lines
2.7 KiB
C#

using System.Security.Cryptography;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace timetracker.Data;
public class AuthService(IDbContextFactory<TimetrackerDbContext> factory)
{
public async Task<User?> LoginAsync(string username, string password)
{
await using var db = await factory.CreateDbContextAsync();
var user = await db.Users
.FirstOrDefaultAsync(u => u.Username == username);
if (user == null) return null;
return VerifyPassword(password, user.PasswordHash, user.PasswordSalt) ? user : null;
}
public async Task<List<User>> GetAllUsersAsync()
{
await using var db = await factory.CreateDbContextAsync();
return await db.Users
.OrderBy(u => u.Username)
.ToListAsync();
}
public async Task DeleteUserAsync(int userId)
{
await using var db = await factory.CreateDbContextAsync();
var user = await db.Users.FindAsync(userId);
if (user != null)
{
db.Users.Remove(user);
await db.SaveChangesAsync();
}
}
public async Task<(User? User, string? Error)> RegisterAsync(string username, string password) {
if (string.IsNullOrWhiteSpace(username) || username.Length < 3)
return (null, "Benutzername muss mindestens 3 Zeichen lang sein.");
if (string.IsNullOrWhiteSpace(password) || password.Length < 6)
return (null, "Passwort muss mindestens 6 Zeichen lang sein.");
await using var db = await factory.CreateDbContextAsync();
if (await db.Users.AnyAsync(u => u.Username == username))
return (null, "Benutzername bereits vergeben.");
var (hash, salt) = HashPassword(password);
var user = new User { Username = username, PasswordHash = hash, PasswordSalt = salt };
db.Users.Add(user);
await db.SaveChangesAsync();
return (user, null);
}
private static (string hash, string salt) HashPassword(string password)
{
var saltBytes = RandomNumberGenerator.GetBytes(32);
var salt = Convert.ToBase64String(saltBytes);
var hash = ComputeHash(password, salt);
return (hash, salt);
}
private static bool VerifyPassword(string password, string hash, string salt)
=> ComputeHash(password, salt) == hash;
private static string ComputeHash(string password, string salt)
{
var hash = Rfc2898DeriveBytes.Pbkdf2(
Encoding.UTF8.GetBytes(password),
Convert.FromBase64String(salt),
iterations: 200_000,
HashAlgorithmName.SHA256,
outputLength: 32);
return Convert.ToBase64String(hash);
}
}