Files
T120B165/T120B165-ImgBoard/Controllers/AuthController.cs

101 lines
3.9 KiB
C#

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using T120B165_ImgBoard.Dtos;
using T120B165_ImgBoard.Models;
using T120B165_ImgBoard.Services;
namespace T120B165_ImgBoard.Controllers;
[ApiController]
[Route("api/auth")]
public class AuthController(UserManager<User> userManager, ITokenService tokenService): ControllerBase
{
/// <summary>
/// Creates a new user account.
/// </summary>
/// <param name="dto">Registration data</param>
/// <response code="200">Returns user data</response>
/// <response code="400">If user supplied credentials fail validation</response>
[HttpPost("register")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<SlimUserDto>> Register(RegisterDto dto)
{
var user = new User
{
UserName = dto.UserName,
Email = dto.Email,
};
var result = await userManager.CreateAsync(user, dto.Password);
await userManager.AddToRoleAsync(user, UserRoles.Regular);
if (!result.Succeeded)
{
return BadRequest(result.Errors);
}
return Ok(SlimUserDto.FromUser(user));
}
/// <summary>
/// Authenticates and creates a pair of access and refresh tokens.
/// </summary>
/// <param name="dto">Data with refresh token</param>
/// <response code="200">Returns refresh and access tokens</response>
/// <response code="401">If the credentials are incorrect</response>
[HttpPost("login")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<TokenDto>> Login(LoginDto dto)
{
var user = await userManager.FindByEmailAsync(dto.Email);
if (user == null || !await userManager.CheckPasswordAsync(user, dto.Password))
return Unauthorized();
var accessToken = await tokenService.GenerateJwtToken(user);
var refreshToken = await tokenService.GenerateRefreshToken(user);
return Ok(new TokenDto(AccessToken: accessToken, RefreshToken: refreshToken));
}
/// <summary>
/// Consume refresh token to create new access and refresh tokens.
/// </summary>
/// <param name="dto">Data with refresh token</param>
/// <response code="200">Returns new refresh and access tokens</response>
/// <response code="401">If refresh token is missing or is expired</response>
[HttpPost("refresh")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<TokenDto>> Refresh(RefreshDto dto)
{
var token = await tokenService.GetRefreshTokenByValue(dto.RefreshToken);
if (token == null) return Unauthorized();
var user = token.User;
await tokenService.InvalidateRefreshToken(token);
var accessToken = await tokenService.GenerateJwtToken(user);
var newRefreshToken = await tokenService.GenerateRefreshToken(user);
return Ok(new TokenDto(AccessToken: accessToken, RefreshToken: newRefreshToken));
}
/// <summary>
/// Revokes the refresh token.
/// </summary>
/// <param name="dto">Data with refresh token</param>
/// <response code="204">If token was revoked successfully</response>
/// <response code="401">If refresh token is missing or is expired</response>
[HttpPost("revoke")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<TokenDto>> Revoke(RefreshDto dto)
{
var token = await tokenService.GetRefreshTokenByValue(dto.RefreshToken);
if (token == null) return Unauthorized();
await tokenService.InvalidateRefreshToken(token);
return NoContent();
}
}