MireaBackend/Endpoint/Controllers/V1/AuthController.cs

132 lines
4.7 KiB
C#

using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Mirea.Api.Dto.Common;
using Mirea.Api.Dto.Requests;
using Mirea.Api.Dto.Responses;
using Mirea.Api.Endpoint.Common.Attributes;
using Mirea.Api.Endpoint.Common.Exceptions;
using Mirea.Api.Endpoint.Common.MapperDto;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration.Model;
using Mirea.Api.Security.Common.Domain;
using Mirea.Api.Security.Services;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Controllers.V1;
[ApiVersion("1.0")]
public class AuthController(IOptionsSnapshot<Admin> user, AuthService auth, PasswordHashService passwordService) : BaseController
{
private CookieOptionsParameters GetCookieParams() =>
new()
{
Domain = HttpContext.GetCurrentDomain(),
Path = UrlHelper.GetSubPathWithoutFirstApiName + "api"
};
[HttpGet("GetAvailableProviders")]
public ActionResult<List<AvailableProvidersResponse>> GetUrls() =>
Ok(oAuthService
.GetAvailableProviders(HttpContext, GetCookieParams(), HttpContext.GetApiUrl(Url.Action("OAuth2")!))
.ConvertToDto());
[HttpPost("Login")]
[BadRequestResponse]
public async Task<ActionResult<TwoFactorAuthentication>> Login([FromBody] LoginRequest request)
{
var userEntity = user.Value;
if (!userEntity.Username.Equals(request.Username, StringComparison.OrdinalIgnoreCase) &&
!userEntity.Email.Equals(request.Username, StringComparison.OrdinalIgnoreCase))
return Unauthorized("Authentication failed. Please check your credentials.");
var tokenResult = await auth.LoginAsync(
GetCookieParams(),
new User
{
Id = 1.ToString(),
Username = userEntity.Username,
Email = userEntity.Email,
PasswordHash = userEntity.PasswordHash,
Salt = userEntity.Salt,
TwoFactorAuthenticator = userEntity.TwoFactorAuthenticator,
SecondFactorToken = userEntity.Secret,
OAuthProviders = userEntity.OAuthProviders
},
HttpContext, request.Password);
return Ok(tokenResult.ConvertToDto());
}
[HttpPost("2FA")]
[BadRequestResponse]
public async Task<ActionResult<bool>> TwoFactorAuth([FromBody] TwoFactorAuthRequest request)
{
var tokenResult = await auth.LoginAsync(GetCookieParams(), HttpContext, request.Method.ConvertFromDto(), request.Code);
return Ok(tokenResult);
}
/// <summary>
/// Refreshes the authentication token using the existing refresh token.
/// </summary>
/// <returns>User's AuthRoles.</returns>
[HttpGet("ReLogin")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<AuthRoles>> ReLogin()
{
await auth.RefreshTokenAsync(GetCookieParams(), HttpContext);
return Ok(AuthRoles.Admin);
}
/// <summary>
/// Logs the user out by clearing the refresh token and performing any necessary cleanup.
/// </summary>
/// <returns>An Ok response if the logout was successful.</returns>
[HttpGet("Logout")]
public async Task<ActionResult> Logout()
{
await auth.LogoutAsync(GetCookieParams(), HttpContext);
return Ok();
}
/// <summary>
/// Retrieves the role of the authenticated user.
/// </summary>
/// <returns>The role of the authenticated user.</returns>
[HttpGet("GetRole")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public ActionResult<AuthRoles> GetRole() => Ok(AuthRoles.Admin);
[HttpPost("RenewPassword")]
[ApiExplorerSettings(IgnoreApi = true)]
[Localhost]
[BadRequestResponse]
public ActionResult<string> RenewPassword([FromBody] string? password = null)
{
if (string.IsNullOrEmpty(password))
password = string.Empty;
else if (!PasswordHashService.HasPasswordInPolicySecurity(password))
throw new ControllerArgumentException("The password must be at least 8 characters long and contain at least one uppercase letter and one special character.");
while (!PasswordHashService.HasPasswordInPolicySecurity(password))
password = GeneratorKey.GenerateAlphaNumeric(16, includes: "!@#%^");
var (salt, hash) = passwordService.HashPassword(password);
var admin = user.Value;
admin.Salt = salt;
admin.PasswordHash = hash;
admin.SaveSetting();
return Ok(password);
}
}