using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using SlipItIn.Server.Data; using SlipItIn.Shared.DTOs; using SlipItIn.Shared.Models; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace SlipItIn.Server.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly IDbContextFactory _contextFactory; private readonly IConfiguration _configuration; private readonly IHostEnvironment _environment; public AuthController(IDbContextFactory contextFactory, IConfiguration configuration, IHostEnvironment environment) { _contextFactory = contextFactory; _configuration = configuration; _environment = environment; } [HttpPost("register")] public async Task> Register(RegisterRequestDto request) { if (string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) return BadRequest("Username, Email und Passwort sind erforderlich."); if (request.Password.Length < 8) return BadRequest("Das Passwort muss mindestens 8 Zeichen lang sein."); using var context = _contextFactory.CreateDbContext(); var normalizedEmail = request.Email.Trim().ToLowerInvariant(); var normalizedUsername = request.Username.Trim(); var emailExists = await context.Users.AnyAsync(u => u.Email.ToLower() == normalizedEmail); if (emailExists) return Conflict("Email ist bereits vergeben."); var usernameExists = await context.Users.AnyAsync(u => u.Username.ToLower() == normalizedUsername.ToLower()); if (usernameExists) return Conflict("Username ist bereits vergeben."); var user = new User { Username = normalizedUsername, Email = normalizedEmail, PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password) }; context.Users.Add(user); await context.SaveChangesAsync(); return Ok(CreateAuthResponse(user)); } [HttpPost("login")] public async Task> Login(LoginRequestDto request) { if (string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password)) return BadRequest("Email und Passwort sind erforderlich."); using var context = _contextFactory.CreateDbContext(); var normalizedEmail = request.Email.Trim().ToLowerInvariant(); var user = await context.Users.FirstOrDefaultAsync(u => u.Email.ToLower() == normalizedEmail); if (user is null || !BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash)) return Unauthorized("Ungültige Anmeldedaten."); return Ok(CreateAuthResponse(user)); } [Authorize] [HttpGet("me")] public ActionResult Me() { var userIdClaim = User.FindFirstValue(ClaimTypes.NameIdentifier); var username = User.FindFirstValue(ClaimTypes.Name); var email = User.FindFirstValue(ClaimTypes.Email); if (string.IsNullOrWhiteSpace(userIdClaim)) return Unauthorized(); return Ok(new { UserId = int.TryParse(userIdClaim, out var parsedUserId) ? parsedUserId : 0, Username = username, Email = email }); } private AuthResponseDto CreateAuthResponse(User user) { var jwtKey = _configuration["Jwt:Key"]; if (string.IsNullOrWhiteSpace(jwtKey)) { if (!_environment.IsDevelopment()) throw new InvalidOperationException("Jwt:Key ist nicht konfiguriert."); jwtKey = "DevOnlyKey-NotForProduction-ChangeMe-0123456789abcdef"; } var jwtIssuer = _configuration["Jwt:Issuer"] ?? "SlipItInServer"; var jwtAudience = _configuration["Jwt:Audience"] ?? "SlipItInClient"; var expirationMinutes = int.TryParse(_configuration["Jwt:ExpirationMinutes"], out var parsedMinutes) ? parsedMinutes : 1440; var expiresAt = DateTime.UtcNow.AddMinutes(expirationMinutes); var claims = new List { new(ClaimTypes.NameIdentifier, user.Id.ToString()), new(ClaimTypes.Name, user.Username), new(ClaimTypes.Email, user.Email) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: jwtIssuer, audience: jwtAudience, claims: claims, expires: expiresAt, signingCredentials: credentials); return new AuthResponseDto { Token = new JwtSecurityTokenHandler().WriteToken(token), ExpiresAtUtc = expiresAt, UserId = user.Id, Username = user.Username, Email = user.Email }; } }