using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using agologumApi.Models; using agologumApi.Services; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { // identity things private readonly UserManager userManager_; private readonly SignInManager signInManager_; private readonly JwtService jwt_; public AuthController(UserManager userManager, SignInManager signInManager, JwtService jwt) { userManager_ = userManager; signInManager_ = signInManager; jwt_ = jwt; } [HttpPost("register")] public async Task Register(RegisterDto dto) { var user = new User { UserName = dto.UserName, Email = dto.Email, CreatedAt = DateTime.UtcNow // yeah why not utc }; var result = await userManager_.CreateAsync(user, dto.Password); if(!result.Succeeded) return BadRequest(result.Errors); // assigning roles to user string role = "base"; if(dto.UserName == "bard") { role = "superuser"; } else if(dto.UserName.StartsWith("x")) { role = "admin"; } await userManager_.AddToRoleAsync(user, role); // TODO: error check this // these are here just in case you need them // await _userManager.RemoveFromRoleAsync(user, "admin"); // remove role // var roles = await _userManager.GetRolesAsync(user); // get list of roles for user return CreatedAtAction( nameof(Register), new { id = user.Id } ); } [HttpPost("login")] public async Task Login(LoginDto dto) { var user = await userManager_.FindByNameAsync(dto.UserName); if (user == null) return Unauthorized(); var result = await signInManager_.CheckPasswordSignInAsync(user, dto.Password, false); if(!result.Succeeded) return Unauthorized(); var accessToken = jwt_.GenerateJwt(user); var refreshToken = jwt_.GenerateRefreshToken(); RefreshToken newTokenObject = new RefreshToken { Token = refreshToken, UserId = user.Id, CreatedAt = DateTime.UtcNow, ExpiresAt = DateTime.UtcNow.AddDays(30), IsRevoked = false }; await jwt_.AddRefreshToken(newTokenObject); return Ok(new { accessToken, refreshToken }); } [Authorize] // authorize is handled by middleware [HttpPost("logout")] public async Task Logout(string refreshTokenString) { // revoke refresh token bool success = await jwt_.RevokeRefreshToken(refreshTokenString); if(!success) return NotFound(); return Ok(); } [HttpPost("refresh")] // allow-anonymous by default public async Task Refresh(TokenDto request) { RefreshToken? storedToken = await jwt_.GetRefreshToken(request.RefreshToken); if (storedToken == null) return Unauthorized(); bool valid = (storedToken.IsRevoked) || (storedToken.ExpiresAt < DateTime.UtcNow); if(!valid) return Unauthorized(); // TODO: delete the invalid token User? user = await jwt_.GetUser(storedToken.UserId); if(user == null) return NotFound(); string? newAccessToken = await jwt_.GenerateJwt(user); if(newAccessToken == null) return NotFound(); string newRefreshToken = jwt_.GenerateRefreshToken(); storedToken.IsRevoked = true; RefreshToken newTokenObject = new RefreshToken { Token = newRefreshToken, UserId = storedToken.UserId, CreatedAt = DateTime.UtcNow, ExpiresAt = DateTime.UtcNow.AddDays(30), IsRevoked = false }; await jwt_.AddRefreshToken(newTokenObject); return Ok(new { accessToken = newAccessToken, refreshToken = newRefreshToken }); } // TODO // email verification // password reset // oh hell naw 2FA I do not care enough }