Files
SlipItIn/SlipItIn.Server/Controllers/AuthController.cs
Tim Krampitz 070727d5cd JWT-Authentifizierung & GameState-Verbesserungen
Neuer AuthController mit Endpunkten für Registrierung, Login und Nutzerinfo (/register, /login, /me) implementiert. Auth-spezifische DTOs hinzugefügt. GameHub mit [Authorize] geschützt und Spielteilnahme validiert. GameService liefert jetzt Rundeninfos, aktuelle Rundennummer und verbleibende Rundendauer. Migrations-Ordner im Projekt angelegt.
2026-07-26 13:30:03 +02:00

130 lines
4.6 KiB
C#

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<SlipItInDbContext> _contextFactory;
private readonly IConfiguration _configuration;
public AuthController(IDbContextFactory<SlipItInDbContext> contextFactory, IConfiguration configuration)
{
_contextFactory = contextFactory;
_configuration = configuration;
}
[HttpPost("register")]
public async Task<ActionResult<AuthResponseDto>> Register(RegisterRequestDto request)
{
if (string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Email) || string.IsNullOrWhiteSpace(request.Password))
return BadRequest("Username, Email und Passwort sind erforderlich.");
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<ActionResult<AuthResponseDto>> 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<object> 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.Parse(userIdClaim),
Username = username,
Email = email
});
}
private AuthResponseDto CreateAuthResponse(User user)
{
var jwtKey = _configuration["Jwt:Key"] ?? "YourSuperSecretKeyThatIsAtLeast32CharactersLong!";
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<Claim>
{
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
};
}
}