2024-09-18 06:00:07 +03:00
using Asp.Versioning ;
using Microsoft.AspNetCore.Authorization ;
2024-06-21 21:52:21 +03:00
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Extensions.Options ;
using Mirea.Api.Dto.Common ;
using Mirea.Api.Dto.Requests ;
2024-10-31 04:12:02 +03:00
using Mirea.Api.Dto.Responses ;
2024-08-24 04:30:31 +03:00
using Mirea.Api.Endpoint.Common.Attributes ;
2024-08-27 22:52:07 +03:00
using Mirea.Api.Endpoint.Common.Exceptions ;
2024-07-05 01:35:19 +03:00
using Mirea.Api.Endpoint.Common.Services ;
2024-10-07 02:13:35 +03:00
using Mirea.Api.Endpoint.Configuration.Model ;
2024-10-31 04:12:02 +03:00
using Mirea.Api.Security.Common.Domain ;
2024-06-21 21:52:21 +03:00
using Mirea.Api.Security.Services ;
using System ;
using System.Threading.Tasks ;
namespace Mirea.Api.Endpoint.Controllers.V1 ;
[ApiVersion("1.0")]
2024-10-31 04:12:02 +03:00
public class AuthController ( IOptionsSnapshot < Admin > user , AuthService auth , PasswordHashService passwordService ) : BaseController
2024-06-21 21:52:21 +03:00
{
2024-10-31 04:12:02 +03:00
private CookieOptionsParameters GetCookieParams ( ) = >
new ( )
2024-06-21 21:52:21 +03:00
{
2024-08-10 23:11:43 +03:00
Domain = HttpContext . GetCurrentDomain ( ) ,
2024-10-31 04:12:02 +03:00
Path = UrlHelper . GetSubPathWithoutFirstApiName + "api"
2024-06-21 21:52:21 +03:00
} ;
[HttpPost("Login")]
2024-10-09 03:00:26 +03:00
[BadRequestResponse]
2024-10-31 04:12:02 +03:00
public async Task < ActionResult < AuthenticationStep > > Login ( [ FromBody ] LoginRequest request )
2024-06-21 21:52:21 +03:00
{
var userEntity = user . Value ;
if ( ! userEntity . Username . Equals ( request . Username , StringComparison . OrdinalIgnoreCase ) & &
2024-10-31 04:12:02 +03:00
! userEntity . Email . Equals ( request . Username , StringComparison . OrdinalIgnoreCase ) )
2024-10-09 03:00:26 +03:00
return BadRequest ( "Invalid username/email or password" ) ;
2024-06-21 21:52:21 +03:00
2024-10-31 04:12:02 +03:00
var tokenResult = await auth . LoginAsync (
GetCookieParams ( ) ,
new User
{
Id = 1 ,
Username = userEntity . Username ,
Email = userEntity . Email ,
PasswordHash = userEntity . PasswordHash ,
Salt = userEntity . Salt ,
SecondFactor = userEntity . SecondFactor ,
SecondFactorToken = userEntity . Secret
} ,
HttpContext , request . Password ) ;
return Ok ( tokenResult ? AuthenticationStep . None : AuthenticationStep . TotpRequired ) ;
}
2024-06-21 21:52:21 +03:00
2024-10-31 04:12:02 +03:00
[HttpGet("Login")]
[BadRequestResponse]
public async Task < ActionResult < AuthenticationStep > > Login ( [ FromQuery ] string code )
{
var tokenResult = await auth . LoginAsync ( GetCookieParams ( ) , HttpContext , code ) ;
return Ok ( tokenResult ? AuthenticationStep . None : AuthenticationStep . TotpRequired ) ;
2024-06-21 21:52:21 +03:00
}
2024-06-28 22:55:18 +03:00
/// <summary>
/// Refreshes the authentication token using the existing refresh token.
/// </summary>
2024-10-09 03:00:26 +03:00
/// <returns>User's AuthRoles.</returns>
2024-06-21 21:52:21 +03:00
[HttpGet("ReLogin")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
2024-10-09 03:00:26 +03:00
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task < ActionResult < AuthRoles > > ReLogin ( )
2024-06-21 21:52:21 +03:00
{
2024-10-31 04:12:02 +03:00
await auth . RefreshTokenAsync ( GetCookieParams ( ) , HttpContext ) ;
return Ok ( AuthRoles . Admin ) ;
2024-06-21 21:52:21 +03:00
}
2024-06-28 22:55:18 +03:00
/// <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>
2024-06-21 21:52:21 +03:00
[HttpGet("Logout")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task < ActionResult > Logout ( )
{
2024-10-31 04:12:02 +03:00
await auth . LogoutAsync ( GetCookieParams ( ) , HttpContext ) ;
2024-06-21 21:52:21 +03:00
return Ok ( ) ;
}
2024-06-28 22:55:18 +03:00
/// <summary>
/// Retrieves the role of the authenticated user.
/// </summary>
/// <returns>The role of the authenticated user.</returns>
2024-06-21 21:52:21 +03:00
[HttpGet("GetRole")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public ActionResult < AuthRoles > GetRole ( ) = > Ok ( AuthRoles . Admin ) ;
2024-08-27 22:52:07 +03:00
[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 ) ;
}
2024-06-21 21:52:21 +03:00
}