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 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 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 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 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 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> 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 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 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; } }