using GameAuthApi.Models; using GameAuthApi.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; namespace GameAuthApi.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly UserService _userService; private readonly IConfiguration _config; private readonly BlacklistService _blacklistService; public AuthController(UserService userService, IConfiguration config, BlacklistService blacklistService) { _userService = userService; _config = config; _blacklistService = blacklistService; } [HttpPost("register")] public async Task Register([FromBody] RegisterRequest credentials) { if (await _userService.GetByUsernameAsync(credentials.Username) != null) return BadRequest("User already exists"); var hash = BCrypt.Net.BCrypt.HashPassword(credentials.Password); var user = new User { Username = credentials.Username, PasswordHash = hash, Role = "USER", Email = credentials.Email }; await _userService.CreateAsync(user); return Ok("User created"); } [HttpPost("login")] public async Task Login([FromBody] LoginRequest credentials) { var user = await _userService.GetByUsernameAsync(credentials.Username); if (user == null || !BCrypt.Net.BCrypt.Verify(credentials.Password, user.PasswordHash)) return Unauthorized(); var accessToken = GenerateJwtToken(user); var refreshToken = Guid.NewGuid().ToString(); var refreshExpiry = DateTime.UtcNow.AddDays(7); user.RefreshToken = refreshToken; user.RefreshTokenExpiry = refreshExpiry; await _userService.UpdateAsync(user); return Ok(new { accessToken, refreshToken, user.Role }); } [HttpPost("refresh")] public async Task Refresh([FromBody] RefreshRequest req) { var user = await _userService.GetByUsernameAsync(req.Username); if (user == null || user.RefreshToken != req.RefreshToken || user.RefreshTokenExpiry < DateTime.UtcNow) return Unauthorized("Invalid or expired refresh token"); var newAccessToken = GenerateJwtToken(user); return Ok(new { accessToken = newAccessToken }); } [HttpPost("logout")] [Authorize(Roles = "USER,SUPER")] public async Task Logout() { var token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", ""); if (string.IsNullOrWhiteSpace(token)) return BadRequest("Token missing"); var jwtToken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken; var expiry = jwtToken.ValidTo; await _blacklistService.AddToBlacklistAsync(token, expiry); return Ok("Token blacklisted, user logged out."); } [HttpPost("role")] [Authorize(Roles = "SUPER")] public async Task ChangeUserRole([FromBody] ChangeRoleRequest request) { if (request.NewRole != "USER" && request.NewRole != "SUPER") return BadRequest("Role must be 'USER' or 'SUPER'"); var user = await _userService.GetByUsernameAsync(request.Username); if (user == null) return NotFound("User not found"); user.Role = request.NewRole; await _userService.UpdateAsync(user); return Ok($"{request.Username}'s role updated to {request.NewRole}"); } [HttpGet("users")] [Authorize(Roles = "SUPER")] public async Task GetAllUsers() { var users = await _userService.GetAllAsync(); return Ok(users); } private string GenerateJwtToken(User user) { var key = Encoding.UTF8.GetBytes(_config["Jwt:Key"]); var creds = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(ClaimTypes.Name, user.Username), new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Role, user.Role) }; var token = new JwtSecurityToken( _config["Jwt:Issuer"], _config["Jwt:Issuer"], claims, expires: DateTime.UtcNow.AddMinutes(15), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } public class RefreshRequest { public string Username { get; set; } public string RefreshToken { get; set; } } }