littleshop/LittleShop/Services/AuthService.cs
2025-09-04 21:28:47 +01:00

230 lines
6.6 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using LittleShop.Data;
using LittleShop.Models;
using LittleShop.DTOs;
namespace LittleShop.Services;
public class AuthService : IAuthService
{
private readonly LittleShopContext _context;
private readonly IConfiguration _configuration;
public AuthService(LittleShopContext context, IConfiguration configuration)
{
_context = context;
_configuration = configuration;
}
public async Task<AuthResponseDto?> LoginAsync(LoginDto loginDto)
{
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Username == loginDto.Username && u.IsActive);
if (user == null || !VerifyPassword(loginDto.Password, user.PasswordHash))
{
return null;
}
var token = GenerateJwtToken(user);
return new AuthResponseDto
{
Token = token,
Username = user.Username,
ExpiresAt = DateTime.UtcNow.AddHours(24)
};
}
public async Task<bool> SeedDefaultUserAsync()
{
if (await _context.Users.AnyAsync())
{
return true;
}
var defaultUser = new User
{
Id = Guid.NewGuid(),
Username = "admin",
PasswordHash = HashPassword("admin"),
CreatedAt = DateTime.UtcNow,
IsActive = true
};
_context.Users.Add(defaultUser);
await _context.SaveChangesAsync();
return true;
}
public async Task<UserDto?> CreateUserAsync(CreateUserDto createUserDto)
{
if (await _context.Users.AnyAsync(u => u.Username == createUserDto.Username))
{
return null;
}
var user = new User
{
Id = Guid.NewGuid(),
Username = createUserDto.Username,
PasswordHash = HashPassword(createUserDto.Password),
CreatedAt = DateTime.UtcNow,
IsActive = true
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
return new UserDto
{
Id = user.Id,
Username = user.Username,
CreatedAt = user.CreatedAt,
IsActive = user.IsActive
};
}
public async Task<UserDto?> GetUserByIdAsync(Guid id)
{
var user = await _context.Users.FindAsync(id);
if (user == null) return null;
return new UserDto
{
Id = user.Id,
Username = user.Username,
CreatedAt = user.CreatedAt,
IsActive = user.IsActive
};
}
public async Task<UserDto?> GetUserByUsernameAsync(string username)
{
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Username == username && u.IsActive);
if (user == null) return null;
return new UserDto
{
Id = user.Id,
Username = user.Username,
CreatedAt = user.CreatedAt,
IsActive = user.IsActive
};
}
public async Task<IEnumerable<UserDto>> GetAllUsersAsync()
{
return await _context.Users
.Select(u => new UserDto
{
Id = u.Id,
Username = u.Username,
CreatedAt = u.CreatedAt,
IsActive = u.IsActive
})
.ToListAsync();
}
public async Task<bool> DeleteUserAsync(Guid id)
{
var user = await _context.Users.FindAsync(id);
if (user == null) return false;
user.IsActive = false;
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> UpdateUserAsync(Guid id, UpdateUserDto updateUserDto)
{
var user = await _context.Users.FindAsync(id);
if (user == null) return false;
if (!string.IsNullOrEmpty(updateUserDto.Username))
{
if (await _context.Users.AnyAsync(u => u.Username == updateUserDto.Username && u.Id != id))
{
return false;
}
user.Username = updateUserDto.Username;
}
if (!string.IsNullOrEmpty(updateUserDto.Password))
{
user.PasswordHash = HashPassword(updateUserDto.Password);
}
if (updateUserDto.IsActive.HasValue)
{
user.IsActive = updateUserDto.IsActive.Value;
}
await _context.SaveChangesAsync();
return true;
}
private string GenerateJwtToken(User user)
{
var jwtKey = _configuration["Jwt:Key"] ?? "YourSuperSecretKeyThatIsAtLeast32CharactersLong!";
var jwtIssuer = _configuration["Jwt:Issuer"] ?? "LittleShop";
var jwtAudience = _configuration["Jwt:Audience"] ?? "LittleShop";
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(jwtKey);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username)
}),
Expires = DateTime.UtcNow.AddHours(24),
Issuer = jwtIssuer,
Audience = jwtAudience,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
private static string HashPassword(string password)
{
using var rng = RandomNumberGenerator.Create();
var salt = new byte[16];
rng.GetBytes(salt);
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000, HashAlgorithmName.SHA256);
var hash = pbkdf2.GetBytes(32);
var hashBytes = new byte[48];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 32);
return Convert.ToBase64String(hashBytes);
}
private static bool VerifyPassword(string password, string hashedPassword)
{
var hashBytes = Convert.FromBase64String(hashedPassword);
var salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000, HashAlgorithmName.SHA256);
var hash = pbkdf2.GetBytes(32);
for (int i = 0; i < 32; i++)
{
if (hashBytes[i + 16] != hash[i])
return false;
}
return true;
}
}