Compartir vía


Configuración de la autenticación web (UI) de OpenID Connect en ASP.NET Core

De Damien Bowden

Ver o descargar el código de ejemplo

En este artículo se detallan las siguientes áreas:

  • ¿Qué es un cliente interactivo confidencial de OpenID Connect?
  • Creación de un cliente de OpenID Connect en ASP.NET Core
  • Ejemplos de cliente de OpenID Connect con fragmentos de código
  • Uso de clientes de proveedor openID Connect de terceros
  • Back-end para la arquitectura de seguridad de front-end (BFF)
  • Características avanzadas, estándares y extensión de un cliente de OpenID Connect

Para una experiencia alternativa utilizando Microsoft Authentication Library for .NET, Microsoft Identity Web y Microsoft Entra ID, consulte Inicio rápido: Iniciar sesión de usuarios y llamar a la API de Microsoft Graph desde una aplicación web ASP.NET Core (documentación de Azure).

Para ver un ejemplo que utiliza el servidor OIDC de Microsoft Entra External ID, consulte Iniciar sesión de usuarios para una aplicación web ASP.NET Core de ejemplo en un inquilino externo y Una aplicación web ASP.NET Core que autentica usuarios contra Microsoft Entra External ID utilizando Microsoft Identity Web.

¿Qué es un cliente interactivo confidencial de OpenID Connect?

OpenID Connect se puede usar para implementar la autenticación en aplicaciones ASP.NET Core. La manera recomendada es usar un cliente confidencial de OpenID Connect mediante el flujo de código. Se recomienda usar la clave de prueba para intercambio de código por parte de clientes públicos de OAuth (PKCE) para esta implementación. Tanto el cliente de la aplicación como el usuario de la aplicación se autentican en el flujo confidencial. El cliente de aplicación usa un secreto de cliente o una aserción de cliente para autenticarse.

Los clientes públicos de OpenID Connect/OAuth ya no se recomiendan para las aplicaciones web.

El flujo predeterminado funciona como se muestra en el diagrama siguiente:

Cliente confidencial de flujo de código OIDC mediante PKCE

OpenID Connect incluye muchas variaciones y todas las implementaciones de servidor tienen parámetros y requisitos ligeramente diferentes. Algunos servidores no admiten el punto de conexión de información de usuario, algunos todavía no admiten PKCE y otros requieren parámetros especiales en la solicitud de token. Las aserciones de cliente se pueden usar en lugar de secretos de cliente. También existen nuevos estándares que agregan seguridad adicional sobre OpenID Connect Core, por ejemplo, FAPI, CIBA o DPoP para las API de bajada.

Nota:

Desde .NET 9, se usa OAuth 2.0 Solicitudes de autorización push (PAR) RFC 9126 de forma predeterminada, si el servidor OpenID Connect lo admite. Este es un flujo de tres pasos y no un flujo de dos pasos, como se muestra anteriormente. (La solicitud de información de usuario es un paso opcional).

Creación de un cliente de flujo de código de Open ID Connect mediante Razor Pages

En la sección siguiente se muestra cómo implementar un cliente de OpenID Connect en un proyecto de página de ASP.NET Core Razor vacío. La misma lógica se puede aplicar a cualquier proyecto web de ASP.NET Core con solo la integración de la interfaz de usuario siendo diferente.

Adición de compatibilidad con OpenID Connect

Agregue los paquetes nuget de Microsoft.AspNetCore.Authentication.OpenIdConnect al proyecto ASP.NET Core.

Configuración del cliente de OpenID Connect

Agregue la autenticación a la aplicación web usando el builder.Services en el archivo Program.cs. La configuración depende del servidor openID Connect. Cada servidor de OpenID Connect requiere pequeñas diferencias en la configuración.

El controlador openID Connect se usa para los desafíos y el cierre de sesión. cookie se usa para controlar la sesión en la aplicación web. Los esquemas predeterminados para la autenticación se pueden especificar según sea necesario.

Para obtener más información, consulte la guía de ASP.NET Core authentication-handler.

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");

    options.Authority = oidcConfig["Authority"];
    options.ClientId = oidcConfig["ClientId"];
    options.ClientSecret = oidcConfig["ClientSecret"];

    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.MapInboundClaims = false;
    options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
    options.TokenValidationParameters.RoleClaimType = "roles";
});

Para obtener más información sobre las distintas opciones de OpenID Connect, consulte Proteja un ASP.NET Core Blazor Web App con OpenID Connect (OIDC).

Para conocer las distintas posibilidades de asignación de reclamaciones, consulte Asignación, personalización y transformación de reclamaciones en ASP.NET Core.

Nota:

Se requieren los siguientes espacios de nombres:

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

Configuración de las propiedades de configuración

Agregue la configuración de cliente de OpenID Connect a las propiedades de configuración de la aplicación. La configuración debe coincidir con la configuración del cliente en el servidor openID Connect. No se debe persistir ningún secreto en la configuración de la aplicación donde se puedan registrar accidentalmente. Los secretos deben almacenarse en una ubicación segura como Azure Key Vault en entornos de producción o en secretos de usuario en un entorno de desarrollo. Para obtener más información, consulte Almacenamiento seguro de secretos de aplicaciones en desarrollo en ASP.NET Core.

"OpenIDConnectSettings": {
  // OpenID Connect URL. (The base URL for the /.well-known/openid-configuration)
  "Authority": "<Authority>",
  // client ID from the OpenID Connect server
  "ClientId": "<Client ID>",
  //"ClientSecret": "--stored-in-user-secrets-or-key-vault--"
},

Configuración de la ruta de devolución de llamada firmada

La (clave de configuración: "SignedOutCallbackPath") SignedOutCallbackPath es la ruta de solicitud dentro de la ruta base de la aplicación interceptada por el controlador de OpenID Connect donde se devuelve por primera vez el agente de usuario después de cerrar sesión en el proveedor de identidad. La aplicación de ejemplo no establece un valor para la ruta de acceso porque se usa el valor predeterminado de "/signout-callback-oidc". Después de interceptar la solicitud, el controlador openID Connect redirige al SignedOutRedirectUri o RedirectUri, si se especifica.

Configure la ruta de devolución de llamada de cierre de sesión en el registro del proveedor OIDC de la aplicación. En el ejemplo siguiente, el marcador de posición {PORT} es el puerto de la aplicación:

https://localhost:{PORT}/signout-callback-oidc

Nota:

Cuando utilice Microsoft Entra ID, establezca la ruta en las entradas Redirect URI de la configuración de la plataforma web en el portal Entra o Azure. No se requiere un puerto para direcciones localhost al usar Entra. La mayoría de los demás proveedores de OIDC requieren el puerto correcto. Si no se agrega el URI de la ruta de retorno de llamada de salida al registro de la aplicación en Entra, Entra se niega a redirigir al usuario de vuelta a la aplicación y simplemente le pide que cierre la ventana de su navegador.

Actualice el método de canalización ASP.NET Core en la clase de programa.

El método UseRouting debe implementarse antes del método UseAuthorization.

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
// Authorization is applied for middleware after the UseAuthorization method
app.UseAuthorization();
app.MapRazorPages();

Forzar autorización

Agregue el atributo [Authorize] a las páginas de Razor protegidas:

[Authorize]

Un mejor enfoque es forzar la autorización para toda la aplicación y excluir las páginas no seguras.

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

Agregar una nueva página Logout.cshtml y las páginas SignedOut.cshtmlyRazor al proyecto

Se requiere un cierre de sesión para cerrar sesión tanto en la sesión de cookie como en la sesión de OpenID Connect. Toda la aplicación debe redirigir al servidor openID Connect para cerrar la sesión. Después de cerrar la sesión correctamente, la aplicación abre la ruta RedirectUri.

Implemente una página de cierre de sesión predeterminada y cambie el código de la página Razor Logout a lo siguiente:

[Authorize]
public class LogoutModel : PageModel
{
    public IActionResult OnGetAsync()
    {
        return SignOut(new AuthenticationProperties
        {
            RedirectUri = "/SignedOut"
        },
        // Clear auth cookie
        CookieAuthenticationDefaults.AuthenticationScheme,
        // Redirect to OIDC provider signout endpoint
        OpenIdConnectDefaults.AuthenticationScheme);
    }
}

El SignedOut.cshtml requiere el atributo [AllowAnonymous]:

[AllowAnonymous]
public class SignedOutModel : PageModel
{
    public void OnGet()
    {
    }
}

Implementar una página Login

Una página LoginRazor también puede ser implementada para llamar directamente a la ChallengeAsync con el requerimiento AuthProperties. Esto no es necesario si la aplicación web requiere autenticación y se usa el desafío predeterminado.

La página Login.cshtml requiere el atributo [AllowAnonymous]:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPageOidc.Pages;

[AllowAnonymous]
public class LoginModel : PageModel
{
    [BindProperty(SupportsGet = true)]
    public string? ReturnUrl { get; set; }

    public async Task OnGetAsync()
    {
        var properties = GetAuthProperties(ReturnUrl);
        await HttpContext.ChallengeAsync(properties);
    }

    private static AuthenticationProperties GetAuthProperties(string? returnUrl)
    {
        const string pathBase = "/";

        // Prevent open redirects.
        if (string.IsNullOrEmpty(returnUrl))
        {
            returnUrl = pathBase;
        }
        else if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Relative))
        {
            returnUrl = new Uri(returnUrl, UriKind.Absolute).PathAndQuery;
        }
        else if (returnUrl[0] != '/')
        {
            returnUrl = $"{pathBase}{returnUrl}";
        }

        return new AuthenticationProperties { RedirectUri = returnUrl };
    }
}

Adición de un botón de inicio de sesión y cierre de sesión para el usuario

@if (Context.User.Identity!.IsAuthenticated)
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
	</li>

	<span class="nav-link text-dark">Hi @Context.User.Identity.Name</span>
}
else
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Index">Login</a>
	</li>
}

Ejemplos con fragmentos de código

Ejemplo de uso del punto de conexión de información de usuario

Las opciones de OpenID Connect se pueden usar para asignar notificaciones, implementar controladores o incluso guardar los tokens en la sesión para su uso posterior.

La opción Scope se puede usar para solicitar notificaciones diferentes o un token de actualización que se envía como información al servidor openID Connect. Solicitar el offline_access pide al servidor que devuelva un token de referencia que se puede usar para actualizar la sesión sin volver a autenticar al usuario de la aplicación.

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
    options.Authority = oidcConfig["IdentityProviderUrl"];
    options.ClientSecret = oidcConfig["ClientSecret"];
    options.ClientId = oidcConfig["Audience"];
    options.ResponseType = OpenIdConnectResponseType.Code;

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

    options.ClaimActions.Remove("amr");
    options.ClaimActions.MapUniqueJsonKey("website", "website");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    // .NET 9 feature
    options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Require;

    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "role";
});

Implementación de proveedores de identidades de Microsoft

Microsoft tiene varios proveedores de identidades y implementaciones de OpenID Connect. Microsoft tiene diferentes servidores de OpenID Connect:

  • Microsoft Entra ID
  • Id. externa de Microsoft Entra
  • Azure AD B2C

Si se autentica con uno de los proveedores de identidades de Microsoft en ASP.NET Core, se recomienda usar los paquetes nuget de Microsoft.Identity.Web.

Los paquetes nuget de Microsoft.Identity.Web son un cliente específico de Microsoft basado en el cliente de ASP.NET Core OpenID Connect con algunos cambios en el cliente predeterminado.

Uso de clientes de proveedor openID Connect de terceros

Muchas implementaciones de servidor de OpenID Connect crean paquetes Nuget optimizados para la misma implementación de OpenID Connect. Estos paquetes implementan los detalles del cliente de OpenID Connect con los extras requeridos por el servidor de OpenID Connect específico. Microsoft.Identity.Web es un ejemplo de esto.

Si implementa varios clientes de OpenID Connect de diferentes servidores de OpenID Connect en una sola aplicación, normalmente es mejor revertir a la implementación predeterminada de ASP.NET Core, ya que los distintos clientes sobrescriben algunas opciones que afectan a los demás clientes.

Los proveedores web openIddict son una implementación de cliente que admite muchas implementaciones de servidor diferentes.

IdentityModel es una biblioteca auxiliar estándar de .NET para la identidad basada en notificaciones, OAuth 2.0 y OpenID Connect. Esto también se puede usar para ayudar con la implementación del cliente.

Back-end para la arquitectura de seguridad de front-end (BFF)

Ya no se recomienda implementar clientes públicos de OpenID Connect para ninguna aplicación web.

Para más información, consulte el borrador de OAuth 2.0 para Aplicaciones Basadas en Navegador.

Si se implementan aplicaciones web que no tienen un backend independiente, se recomienda utilizar el patrón de arquitectura de seguridad Backend for Frontend (BFF). Este patrón se puede implementar de maneras diferentes, pero la autenticación siempre se implementa en el back-end y no se envía ningún dato confidencial al cliente web para más flujos de autorización o autenticación.

Características avanzadas, estándares, extensión del cliente OIDC

Registro

La depuración de clientes de OpenID Connect puede ser difícil. Los datos de información de identificación personal (PII) no se registran de forma predeterminada. Si se depura en modo de desarrollo, el IdentityModelEventSource.ShowPII puede utilizarse para registrar datos personales confidenciales. No implemente una aplicación con IdentityModelEventSource.ShowPII en servidores productivos.

//using ...

using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

//... code 

var app = builder.Build();

IdentityModelEventSource.ShowPII = true;

//... code 

app.Run();

Para obtener más información, vea Registro.

Nota:

Es posible que desee reducir el nivel de registro configurado para ver todos los registros necesarios.

Personalización de parámetros de OIDC y OAuth

La opción de los manejadores de autenticación de OAuth y OIDC (AdditionalAuthorizationParameters) permite personalizar los parámetros del mensaje de autorización que normalmente se incluyen como parte de la cadena de consulta de redirección.

Asignación de notificaciones desde OpenID Connect

Para obtener más información, consulte Asignación, personalización y transformación de reclamaciones en ASP.NET Core.

Blazor OpenID Connect

Para obtener más información, consulte Proteger un ASP.NET Core Blazor Web App con OpenID Connect (OIDC).

Estándares