Las aplicaciones modernas se alejan cada vez más de las contraseñas tradicionales y adoptan métodos de autenticación sin contraseña que son más seguros y fáciles para los usuarios. En esta publicación, mostraré cómo autenticar usuarios en una aplicación ASP.NET Core usando FoxIDs con OpenID Connect y habilitar una experiencia de inicio de sesión completamente sin contraseña usando códigos de un solo uso enviados por correo electrónico.

Comenzaremos desde un entorno FoxIDs limpio, crearemos una nueva aplicación web ASP.NET Core, la conectaremos con OpenID Connect y finalmente habilitaremos el inicio de sesión de passwordless con OTP basado en correo electrónico.

Creación de un entorno de desarrollo FoxIDs

Comencé creando un nuevo entorno de desarrollo vacío en FoxIDs. Un entorno limpio simplifica la configuración de la autenticación desde cero y garantiza que pueda replicar estos pasos en su propio tenant.

Entorno vacío FoxIDs

Si no ha utilizado FoxIDs antes, puede crear un tenant gratuito en:

https://www.foxids.com

Cada tenant viene con dos entornos listos para usar para que puedas experimentar libremente.

Configurar autenticación

Comience configurando cómo deben iniciar sesión los usuarios. En este caso, queremos que los usuarios inicien sesión sin contraseña, usando solo su dirección de correo electrónico y una contraseña de un solo uso (OTP) que se les envió.

  1. Seleccione la pestaña Autenticaciones en su entorno FoxIDs.
  2. Haga clic en Predeterminado: IU de inicio de sesión de usuario.
  3. En la sección Autenticación, deshabilite Autenticación con contraseña y habilite Sin contraseña con correo electrónico (contraseña de un solo uso).
  4. Haga clic en Actualizar para guardar los cambios.
Configurar el método de inicio de sesión de autenticación

Esto permite a los usuarios crear una nueva cuenta y proporciona una experiencia sin contraseña en la que se autentican simplemente ingresando su dirección de correo electrónico y el OTP que reciben.

Creando la aplicación ASP.NET Core

A continuación, necesitamos una aplicación para autenticarnos. Puede utilizar Visual Studio o VS Code, cualquier cosa que admita el desarrollo estándar ASP.NET Core.

Lea la publicación “Autenticación sin contraseña en una aplicación ASP.NET Core generada por IA con FoxIDs y OTP basada en correo electrónico” si desea generar la aplicación ASP.NET Core con un mensaje de IA.

Para este tutorial, estoy creando una aplicación ASP.NET Core Razor Pages simple dirigida a .NET 10 en Visual Studio, pero el mismo enfoque funciona para MVC, una aplicación web Blazor o cualquier otro proyecto ASP.NET Core.

Crear aplicación ASP.NET predeterminada

Ejecute la aplicación; la aplicación de muestra se ejecuta localmente en https://localhost:7283/

Ejecute la aplicación ASP.NET predeterminada

Puede encontrar el código de muestra en: https://github.com/ITfoxtec/dotnet.samples/tree/main/WebAppPasswordLessEmail

Configurar la aplicación web en FoxIDs

Ahora que conocemos la dirección local de la aplicación web, podemos registrarla en FoxIDs para que pueda autenticar a los usuarios a través de OpenID Connect.

  1. Seleccione la pestaña Aplicaciones en su entorno FoxIDs.
  2. Elija Nueva aplicación y luego seleccione Aplicación web: OpenID Connect.
  3. En Nombre, ingrese un nombre, por ejemplo: Aplicación web ASP.NET.
  4. En el URI de redireccionamiento, agregue la dirección base de la aplicación: https://localhost:7283/ De forma predeterminada, FoxIDs permite redirigir a cualquier página posterior bajo esta URL base. Si prefiere una validación más estricta, puede solicitar URI de redireccionamiento absoluto.
  5. Haga clic en Crear.
Agregar aplicación en FoxIDs

FoxIDs ahora muestra los detalles de conexión para su nueva aplicación, que incluyen:

  • Authority
  • ID de cliente
  • Secreto del cliente
Aplicación creada en FoxIDs

Copie Authority y ID de cliente en la sección IdentitySettings del proyecto. Almacene el Client Secret en los secretos de usuario .NET localmente o en una variable de entorno segura o un almacén secreto en producción.

Configurar la autenticación en la aplicación ASP.NET

Con la aplicación FoxIDs creada, el siguiente paso es configurar la autenticación en el proyecto ASP.NET Core. Usaremos autenticación de cookies para la sesión local y OpenID Connect para comunicarnos con FoxIDs.

Abra Program.cs y agregue la configuración de autenticación con (builder.Services.AddAuthentication... y app.UseAuthentication()😉:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

// Detailed authentication errors can help locally, but must not be enabled in production.
if (builder.Environment.IsDevelopment())
{
    IdentityModelEventSource.ShowPII = true;
}

// Add authentication with cookie and OpenID Connect
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
    {
        options.Authority = builder.Configuration["IdentitySettings:Authority"];
        options.ClientId = builder.Configuration["IdentitySettings:ClientId"];
        options.ClientSecret = builder.Configuration["IdentitySettings:ClientSecret"];
        options.ResponseType = OpenIdConnectResponseType.Code;
        options.SaveTokens = true;

        options.Scope.Add("email");
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");

        options.MapInboundClaims = false;
        options.TokenValidationParameters.NameClaimType = "sub";
        options.TokenValidationParameters.RoleClaimType = "role";

        options.Events = new OpenIdConnectEvents
        {
            OnTokenValidated = async context =>
            {
                // Custom claims transformation or other logic can be added here.
                await Task.CompletedTask;
            },
            OnAuthenticationFailed = context =>
            {
                if (!builder.Environment.IsDevelopment())
                {
                    return Task.CompletedTask;
                }

                context.HandleResponse();
                context.Response.StatusCode = 500;
                context.Response.ContentType = "text/plain";
                return context.Response.WriteAsync(context.Exception.ToString());
            }
        };
    });

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllers();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapStaticAssets();
app.MapControllers();
app.MapRazorPages()
   .WithStaticAssets();

app.Run();

Agregue los detalles de conexión no secretos FoxIDs a appsettings.json. Mantenga el secreto del cliente fuera del control de código fuente y cárguelo desde los secretos de usuario .NET durante el desarrollo local o desde una variable de entorno segura o un almacén secreto en producción.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "IdentitySettings": {
    "Authority": "https://foxids.com/{tenant}/{environment}/{application}/",
    "ClientId": "your-client-id"
  }
}

Almacene el secreto del cliente localmente sin escribirlo en appsettings.json:

dotnet user-secrets init
dotnet user-secrets set "IdentitySettings:ClientSecret" "your-client-secret"

Reemplace los valores de ejemplo con Authority, ID de cliente y Secreto de cliente de su propio entorno FoxIDs. Nunca revele el verdadero secreto.

Mostrar claims en la página principal

A los efectos de este ejemplo, muestre los claims en la página principal. Abra Index.cshtml y cambie el contenido:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

@if (User.Identity?.IsAuthenticated == true)
{
    <h2 class="mt-4">Claims</h2>
    <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>Type</th>
                <th>Value</th>
            </tr>
        </thead>
        <tbody>
        @foreach (var claim in User.Claims)
        {
            <tr>
                <td>@claim.Type</td>
                <td>@claim.Value</td>
            </tr>
        }
        </tbody>
    </table>
}
else
{
    <p class="mt-4 text-muted">Not signed in.</p>
}

Agregar un menú de inicio de sesión a la aplicación

Para permitir que los usuarios inicien sesión, agregamos una vista parcial para los controles de inicio y cierre de sesión.

Cree un nuevo archivo: Pages/Shared/_LoginPartial.cshtml con el contenido:

@if (User.Identity?.IsAuthenticated == true)
{
    <ul class="navbar-nav">
        <li class="nav-item">
            <form class="form-inline" asp-controller="Auth" asp-action="Logout" method="post">
                @Html.AntiForgeryToken()
                <button type="submit" class="nav-link btn btn-link text-dark">Log off</button>
            </form>
        </li>
    </ul>
}
else
{
    <ul class="navbar-nav navbar-right">
        <li class="nav-item">
            <a class="nav-link text-dark" asp-controller="Auth" asp-action="Login">Log in</a>
        </li>
    </ul>
}

Luego incluya el inicio de sesión parcial en el menú de navegación. En Pages/Shared/_Layout.cshtml agregue el elemento de inicio de sesión parcial al final de la barra de navegación:

<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
    <ul class="navbar-nav flex-grow-1">
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
        </li>
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
        </li>
    </ul>
    <partial name="_LoginPartial" />
</div>

Luego agregue una página de inicio para las solicitudes de inicio y cierre de sesión. Cree una carpeta Controladores y cree un nuevo archivo de controlador en la carpeta: Controllers/AuthController.cs con el contenido:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace WebAppPasswordLessEmail.Controllers
{
    [AllowAnonymous]
    [Route("[controller]/[action]")]
    public class AuthController : Controller
    {
        [HttpGet]
        public IActionResult Login()
        {
            var redirectUri = Url.Content("~/");
            if (User.Identity?.IsAuthenticated == true)
            {
                return LocalRedirect(redirectUri);
            }

            return Challenge(new AuthenticationProperties { RedirectUri = redirectUri },
                OpenIdConnectDefaults.AuthenticationScheme);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Logout()
        {
            var redirectUri = Url.Content("~/");
            if (User.Identity?.IsAuthenticated != true)
            {
                return LocalRedirect(redirectUri);
            }

            return SignOut(new AuthenticationProperties { RedirectUri = redirectUri },
                CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme);
        }
    }
}

Ejecute y vuelva a cargar la aplicación y ahora verá la opción Iniciar sesión en el menú superior.

Aplicación de muestra

Acceso

Haga clic en Iniciar sesión y será redirigido a la pantalla de inicio de sesión FoxIDs.

Seleccione Crear usuario.

Pantalla de inicio de sesión FoxIDs

Complete el formulario Crear usuario con su correo electrónico (o un correo electrónico de prueba al que tenga acceso), nombre y apellido, luego haga clic en Crear.

Crear un usuario de prueba

Ingrese la contraseña de un solo uso (OTP) que recibió por correo electrónico y luego haga clic en Iniciar sesión.

Inicie sesión con contraseña de un solo uso (OTP)

Ha iniciado sesión y se muestran los claims de su usuario de prueba.

Iniciado sesión, mostrar claims

A continuación, intente cerrar sesión e iniciar sesión nuevamente para experimentar el flujo de inicio de sesión sin contraseña mediante el correo electrónico OTP.