feat: add a token handler

This commit is contained in:
nikita 2024-12-26 16:14:55 +03:00
parent 9d5007ef3a
commit 516ba5bb8e
2 changed files with 80 additions and 1 deletions

View File

@ -0,0 +1,17 @@
namespace Mirea.Api.Dto.Common;
/// <summary>
/// Defines the actions that can be performed with an OAuth token.
/// </summary>
public enum OAuthAction
{
/// <summary>
/// The action to log in the user using the provided OAuth token.
/// </summary>
Login,
/// <summary>
/// The action to bind an OAuth provider to the user's account.
/// </summary>
Bind
}

View File

@ -11,12 +11,13 @@ 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.Model;
using Mirea.Api.Security.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using CookieOptions = Mirea.Api.Security.Common.Model.CookieOptions;
using OAuthProvider = Mirea.Api.Security.Common.Domain.OAuthProvider;
@ -164,6 +165,67 @@ public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<Gener
})
.ConvertToDto());
/// <summary>
/// Processes the OAuth token
/// </summary>
/// <param name="token">The OAuth token used for authentication or binding.</param>
/// <param name="action">The action to be performed: Login or Bind.</param>
/// <returns>If <see cref="OAuthAction.Bind"/> return Ok. If <see cref="OAuthAction.Login"/> return <see cref="TwoFactorAuthentication"/></returns>
[HttpGet("HandleToken")]
[MaintenanceModeIgnore]
[BadRequestResponse]
public async Task<ActionResult> HandleToken([FromQuery][MinLength(2)] string token, [FromQuery] OAuthAction action)
{
var (oAuthUser, error, isSuccess, provider) = await oAuthService.GetOAuthUser(GetCookieParams(), HttpContext, token);
if (!isSuccess || oAuthUser == null || provider == null)
throw new ControllerArgumentException(error ?? "Token processing error.");
switch (action)
{
case OAuthAction.Login:
return Ok(await auth.LoginOAuthAsync(GetCookieParams(), HttpContext, user.Value.ConvertToSecurity(), oAuthUser, provider.Value));
case OAuthAction.Bind:
var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
var admin = user.Value;
if (string.IsNullOrEmpty(userId) || !int.TryParse(userId, out var result) || result != 1)
return Unauthorized(new ProblemDetails
{
Type = "https://tools.ietf.org/html/rfc9110#section-15.5.2",
Title = "Unauthorized",
Status = StatusCodes.Status401Unauthorized,
Detail = "The user is not logged in to link accounts.",
Extensions = new Dictionary<string, object?>()
{
{ "traceId", HttpContext.TraceIdentifier }
}
});
if (admin.OAuthProviders != null && admin.OAuthProviders.ContainsKey(provider.Value))
return Conflict(new ProblemDetails
{
Type = "https://tools.ietf.org/html/rfc9110#section-15.5.10",
Title = "Conflict",
Status = StatusCodes.Status409Conflict,
Detail = "This OAuth provider is already associated with the account.",
Extensions = new Dictionary<string, object?>()
{
{ "traceId", HttpContext.TraceIdentifier }
}
});
admin.OAuthProviders ??= [];
admin.OAuthProviders.Add(provider.Value, oAuthUser);
admin.SaveSetting();
return Ok();
default:
throw new ControllerArgumentException("The action cannot be processed.");
}
}
/// <summary>
/// Logs in a user using their username or email and password.
/// </summary>