Files
gameauthapi/Controllers/AuthController.cs
T

148 lines
4.8 KiB
C#

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