Compartir a través de


Protección de una aplicación hospedada ASP.NET Core Blazor WebAssembly con el identificador de Entra de Microsoft

En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa Microsoft Entra ID (ME-ID) para la autenticación. Este artículo se centra en una aplicación de inquilino único con un único registro de aplicación de Azure de inquilino.

En este artículo no se trata un registro de ME-ID multiinquilino. Para más información, vea Creación de la aplicación multiinquilino.

Este artículo se centra en el uso de un inquilino de Microsoft Entra ID, como se describe en Inicio rápido: Configuración de un inquilino. Si la aplicación está registrada en un inquilino de Azure Active Directory B2C, como se describe en Tutorial: Creación de un inquilino de Azure Active Directory B2C, pero sigue las instrucciones de este artículo, ME-ID administra el URI del identificador de aplicación de forma diferente. Para más información, consulte la sección Uso de un inquilino de Azure Active Directory B2C de este artículo.

Para obtener cobertura de escenarios de seguridad adicionales después de leer este artículo, consulte los escenarios de seguridad adicionales de ASP.NET Core Blazor WebAssembly.

Tutorial

En las subsecciones del tutorial se explica cómo:

  • Crear un inquilino en Azure
  • Registrar una aplicación de API de servidor en Azure
  • Registrar una aplicación cliente en Azure
  • Crear la aplicación Blazor
  • Modificar el archivo de configuración de Server de appsettings.json
  • Modificar el esquema de ámbito de token de acceso predeterminado
  • Ejecutar la aplicación

Crear un inquilino en Azure

Siga las instrucciones de Inicio rápido: Configuración de un inquilino para crear un inquilino en ME-ID.

Registrar una aplicación de API de servidor en Azure

Registre una aplicación de ME-ID para la aplicación de API de servidor:

  1. Vaya a Microsoft Entra ID en Azure portal. Seleccione Aplicaciones>Registros de aplicaciones en la barra lateral. Seleccione el botón Nuevo registro.
  2. Indique un nombre para la aplicación (por ejemplo, Blazor Server ME-ID).
  3. Elija un tipo de cuenta compatible. En esta experiencia puede seleccionar Solo cuentas de este directorio organizativo (inquilino único).
  4. La aplicación de API de servidor no requiere un URI de redireccionamiento en este escenario, así que deje la lista desplegable Seleccionar una plataforma sin seleccionar y no especifique ningún URI de redireccionamiento.
  5. En este artículo se da por supuesto que la aplicación está registrada en un inquilino de Microsoft Entra ID. Si la aplicación está registrada en un inquilino de Azure Active Directory B2C, la casilla Permisos>Conceda consentimiento del administrador a los permisos openid y offline_access está presente y activa. Anule la selección de la casilla para deshabilitar la configuración. Cuando se usa un inquilino de Active Azure Directory, la casilla no está presente.
  6. Seleccione Registrar.

Registra la siguiente información:

  • Identificador de aplicación (cliente) de la aplicación de API de servidor; por ejemplo, 00001111-aaaa-2222-bbbb-3333cccc4444.
  • Identificador de directorio (inquilino); por ejemplo, aaaabbbb-0000-cccc-1111-dddd2222eeee.
  • Dominio de ME-ID Principal/Publicador/Inquilino (por ejemplo, contoso.onmicrosoft.com): el dominio está disponible como Dominio de publicador en la hoja Personalización de marca de Azure Portal de la aplicación registrada.

En los permisos de API, quite el permiso Microsoft Graph>User.Read, ya que la aplicación de API de servidor no requiere acceso de API adicional para simplemente iniciar sesión en usuarios y llamar a puntos de conexión de API de servidor.

En Exponer una API:

  1. Confirme o agregue el URI del identificador de aplicación con el formato api://{SERVER API APP CLIENT ID}.
  2. Seleccione Agregar un ámbito.
  3. Selecciona Guardar y continuar.
  4. Indica un Nombre de ámbito (por ejemplo, API.Access).
  5. Indica un Nombre para mostrar del consentimiento del administrador (por ejemplo, Access API).
  6. Proporciona una Descripción del consentimiento del administrador (por ejemplo, Allows the app to access server app API endpoints.).
  7. Confirma que Estado está establecido en Habilitado.
  8. Selecciona la opción Agregar un ámbito.

Registre la siguiente información:

  • GUID del URI identificador de aplicación (por ejemplo, registro 00001111-aaaa-2222-bbbb-3333cccc4444 del URI del identificador de aplicación de api://00001111-aaaa-2222-bbbb-3333cccc4444)
  • Nombre del ámbito (por ejemplo, API.Access)

Importante

Si se usa un valor personalizado para el URI de identificador de aplicación, se requieren cambios de configuración para las aplicaciones Server y Client después de crearlas a partir de la plantilla de proyecto Blazor WebAssembly. Para obtener más información, consulte la sección Uso de un URI de identificador de aplicación personalizado.

Registrar una aplicación cliente en Azure

Registre una aplicación de ME-ID para la aplicación cliente:

  1. Vaya a Microsoft Entra ID en Azure Portal. Seleccione Registros de aplicaciones en la barra lateral. Seleccione el botón Nuevo registro.
  2. Indique un Nombre para la aplicación (por ejemplo, Blazor Client ME-ID).
  3. Elija un tipo de cuenta compatible. En esta experiencia puede seleccionar Solo cuentas de este directorio organizativo (inquilino único).
  4. Establezca la lista desplegable URI de redireccionamiento en Aplicación de página única (SPA) y proporcione el siguiente URI de redireccionamiento: https://localhost/authentication/login-callback. Si conoces el URI de redirección de producción para el host predeterminado de Azure (por ejemplo, azurewebsites.net) o el host de dominio personalizado (por ejemplo, contoso.com), también puedes agregar el URI de redirección de producción al mismo tiempo que proporciona el URI de localhost redireccionamiento. Asegúrese de incluir el número de puerto para los puertos que no sean puertos:443 en los URI de redirección de producción que agregue.
  5. En este artículo se da por supuesto que la aplicación está registrada en un inquilino de Microsoft Entra ID. Si la aplicación está registrada en un inquilino de Azure Active Directory B2C, la casilla Permisos>Conceda consentimiento del administrador a los permisos openid y offline_access está presente y activa. Anule la selección de la casilla para deshabilitar la configuración. Cuando se usa un inquilino de Active Azure Directory, la casilla no está presente.
  6. Seleccione Registrar.

Nota:

No es necesario proporcionar el número de puerto para una URI de redirección localhost ME-ID. Para obtener más información, consulta Restricciones y limitaciones del URI de redirección (URL de respuesta): excepciones de Localhost (documentación de Entra).

Registre el identificador de la aplicación Client (cliente); por ejemplo, 11112222-bbbb-3333-cccc-4444dddd5555.

En Autenticación>Configuraciones de plataforma>Aplicación de página única:

  1. Confirma que el URI de redirección de https://localhost/authentication/login-callback está presente.
  2. En la sección Concesión implícita, asegúrate de que las casillas Tokens de acceso y Tokens de id. no están seleccionadas. La concesión implícita no se recomienda para las aplicaciones Blazor que usan MSAL v2.0 o posterior. Para obtener más información, consulta Protección de Blazor WebAssembly en ASP.NET Core.
  3. Los valores predeterminados restantes de la aplicación son aceptables en esta experiencia.
  4. Seleccione el botón Guardar si realizó cambios.

En Permisos de API:

  1. Confirme que la aplicación tiene el permiso Microsoft Graph>User.Read.
  2. Seleccione Agregar un permiso, seguido de Mis API.
  3. Seleccione la aplicación de API de servidor en la columna Nombre (por ejemplo, Blazor Server ME-ID). Debe ser propietario del registro de la aplicación (y el registro de la aplicación de API si se trata de una aplicación independiente) para ver la API en el área Mis API de Azure Portal. Para más información, consulta Asignar propietario de la aplicación (documentación de Microsoft Entra).
  4. Abra la lista API.
  5. Habilite el acceso a la API (por ejemplo, API.Access).
  6. Seleccione Agregar permisos.
  7. Selecciona el botón Conceder consentimiento de administrador para {NOMBRE DE INQUILINO} . Selecciona para confirmar la acción.

Importante

Si no tienes la autoridad para conceder el consentimiento de administrador al inquilino en el último paso de la configuración de Permisos de API porque este consentimiento para usar la aplicación se delega a los usuarios, debes seguir los pasos adicionales siguientes:

  • La aplicación debe usar un dominio de publicador de confianza.
  • En la configuración de la aplicación Server en Azure Portal, selecciona Exponer una API. En Aplicaciones cliente autorizadas, selecciona el botón para Agregar una aplicación cliente. Agregue el id. de la aplicación Client (cliente); por ejemplo, 11112222-bbbb-3333-cccc-4444dddd5555.

Crear la aplicación Blazor

Reemplace los marcadores de posición del siguiente comando por la información registrada anteriormente y ejecute el comando en un shell de comandos:

dotnet new blazorwasm -au SingleOrg --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI GUID}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {PROJECT NAME} --tenant-id "{TENANT ID}"

Advertencia

Evita usar guiones (-) en el nombre de la aplicación {PROJECT NAME} que interrumpen la formación del identificador de aplicación de OIDC. La lógica en la plantilla de proyecto de Blazor WebAssembly usa el nombre del proyecto para un identificador de aplicación de OIDC en la configuración de la solución. El uso de las mayúsculas y minúsculas Pascal (BlazorSample) o los guiones bajos (Blazor_Sample) son alternativas aceptables. Para obtener más información, consulta Guiones en un nombre de proyecto hospedado de Blazor WebAssembly interrumpen la seguridad de OIDC (dotnet/aspnetcore #35337).

Marcador de posición Nombre de Azure Portal Ejemplo
{PROJECT NAME} BlazorSample
{CLIENT APP CLIENT ID} Identificador de aplicación (cliente) para la aplicación Client 11112222-bbbb-3333-cccc-4444dddd5555
{DEFAULT SCOPE} Nombre de ámbito API.Access
{SERVER API APP CLIENT ID} Identificador de aplicación (cliente) para la aplicación de API de servidor 00001111-aaaa-2222-bbbb-3333cccc4444
{SERVER API APP ID URI GUID} GUID del URI del identificador de la aplicación 00001111-aaaa-2222-bbbb-3333cccc4444 (GUID ONLY, coincide con {SERVER API APP CLIENT ID})
{TENANT DOMAIN} Dominio Principal/Publicador/Inquilino contoso.onmicrosoft.com
{TENANT ID} Id. de directorio (inquilino) aaaabbbb-0000-cccc-1111-dddd2222eeee

La ubicación de salida especificada con la opción -o|--output crea una carpeta de proyecto si no existe y se convierte en parte del nombre del proyecto. Evite usar guiones (-) en el nombre de la aplicación que interrumpen la formación del identificador de aplicación de OIDC (vea la ADVERTENCIA anterior).

Importante

Si se usa un valor personalizado para el URI de identificador de aplicación, se requieren cambios de configuración para las aplicaciones Server y Client después de crearlas a partir de la plantilla de proyecto Blazor WebAssembly. Para obtener más información, consulte la sección Uso de un URI de identificador de aplicación personalizado.

Ejecutar la aplicación

Ejecuta la aplicación desde el proyecto Server. Al usar Visual Studio, puedes hacer lo siguiente:

  • Selecciona la flecha desplegable situada junto al botón Ejecutar. Abre Configurar proyectos de inicio en la lista desplegable. Selecciona la opción Proyecto de inicio único. Confirma o cambia el proyecto de inicio al proyecto Server.

  • Confirma que el proyecto Server está resaltado en el Explorador de soluciones antes de iniciar la aplicación con cualquiera de los enfoques siguientes:

    • Haz clic en el botón Ejecutar.
    • En el menú, selecciona Depurar>Iniciar depuración.
    • Presiona F5.
  • En un shell de comandos, ve a la carpeta del proyecto Server de la solución. Ejecute el comando dotnet watch (o dotnet run).

Configuración de User.Identity.Name

La guía de esta sección explica cómo, opcionalmente, rellenar User.Identity.Name con el valor de la notificación name.

La API de la aplicación Server rellena User.Identity.Name con el valor del tipo de notificación http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name (por ejemplo, bbbb0000-cccc-1111-dddd-2222eeee3333@contoso.onmicrosoft.com).

Para configurar la aplicación con el fin de recibir el valor del tipo de notificación name:

Partes de la solución

En esta sección se describen las partes de una solución generada a partir de la plantilla de proyecto Blazor WebAssembly y se describe cómo se configuran los proyectos Client y Server de la solución como referencia. No hay ninguna guía específica que se debe seguir en esta sección para una aplicación operativa básica si creaste la aplicación con las instrucciones de la sección Tutorial. Las instrucciones de esta sección son útiles para actualizar una aplicación a fin de autenticar y autorizar a los usuarios. Pero un enfoque alternativo para actualizar una aplicación consiste en crear una aplicación a partir de las instrucciones de la sección Tutorial y mover los componentes, clases y recursos de la aplicación a la nueva aplicación.

Configuración de appsettings.json

Esta sección atañe a la aplicación Server de la solución.

El archivo appsettings.json contiene las opciones para configurar el controlador de portador JWT que se usa para validar los tokens de acceso. Agregue la siguiente sección de configuración de AzureAd:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "{TENANT DOMAIN}",
    "TenantId": "{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "CallbackPath": "/signin-oidc",
    "Scopes": "{SCOPES}"
  }
}

Ejemplo:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "contoso.onmicrosoft.com",
    "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
    "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
    "CallbackPath": "/signin-oidc",
    "Scopes": "API.Access"
  }
}

Importante

Si la aplicación Server está registrada para usar un URI de identificador de aplicación personalizado en ME-ID (no en el formato predeterminado api://{SERVER API APP CLIENT ID}), consulte la sección Uso de un URI de identificador de aplicación personalizado. Se requieren cambios en las aplicaciones Server y Client.

Paquete de autenticación

Esta sección atañe a la aplicación Server de la solución.

El paquete proporciona Microsoft.Identity.Web la compatibilidad para autenticar y autorizar llamadas a ASP.NET API web de Core con la plataforma Microsoftidentity.

Nota:

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

La aplicación Server de una solución Blazor hospedada creada a partir de la plantilla Blazor WebAssembly incluye el paquete Microsoft.Identity.Web.UI. El paquete agrega la interfaz de usuario para la autenticación de usuario en aplicaciones web y el marco Blazor no lo usa. Si la aplicación Server nunca se usará para autenticar a los usuarios directamente, es seguro quitar la referencia de paquete del archivo del proyecto de la aplicación Server.

Compatibilidad con el servicio de autenticación

Esta sección atañe a la aplicación Server de la solución.

El método AddAuthentication configura los servicios de autenticación dentro de la aplicación y, asimismo, configura el controlador de portador JWT como el método de autenticación predeterminado. El AddMicrosoftIdentityWebApi método configura los servicios para proteger la API web con la plataforma de Microsoft identity v2.0. Este método espera una sección AzureAd en la configuración de la aplicación con los ajustes necesarios para inicializar las opciones de autenticación.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));

Nota

Cuando se registra un único esquema de autenticación, se usa automáticamente como esquema predeterminado de la aplicación y no es necesario indicar el esquema a AddAuthentication o a través de AuthenticationOptions. Para obtener más información, consulta:Información general sobre la autenticación de ASP.NET Core y el anuncio de ASP.NET Core (aspnet/Announcements #490).

UseAuthentication y UseAuthorization garantizan que sucede lo siguiente:

  • La aplicación intenta analizar y validar los tokens de las solicitudes entrantes.
  • Cualquier solicitud que intente acceder a un recurso protegido sin las credenciales adecuadas no se realizará correctamente.
app.UseAuthentication();
app.UseAuthorization();

Controlador WeatherForecast

Esta sección atañe a la aplicación Server de la solución.

El controlador WeatherForecast (Controllers/WeatherForecastController.cs) expone una API protegida con el atributo [Authorize] aplicado al controlador. Es importante comprender esto:

  • El atributo [Authorize] en este controlador de API es lo único que protege a esta API de posibles accesos no autorizados.
  • El atributo [Authorize] que se usa en la aplicación Blazor WebAssembly solo sirve como sugerencia a la aplicación de que el usuario debe contar con autorización para que la aplicación funcione correctamente.
[Authorize]
[ApiController]
[Route("[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Configuración de wwwroot/appsettings.json

Esta sección atañe a la aplicación Client de la solución.

La configuración se suministra a través del archivo wwwroot/appsettings.json:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT APP CLIENT ID}",
    "ValidateAuthority": true
  }
}

Ejemplo:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
    "ClientId": "11112222-bbbb-3333-cccc-4444dddd5555",
    "ValidateAuthority": true
  }
}

Paquete de autenticación

Esta sección atañe a la aplicación Client de la solución.

Cuando una aplicación se crea para usar cuentas profesionales o educativas (SingleOrg), la aplicación recibe automáticamente una referencia de paquete de la Biblioteca de autenticación de Microsoft (Microsoft.Authentication.WebAssembly.Msal). El paquete proporciona un conjunto de primitivas que ayudan a la aplicación a autenticar usuarios y a obtener tokens para llamar a API protegidas.

Si agregas autenticación a una aplicación, agregue el paquete Microsoft.Authentication.WebAssembly.Msal manualmente a la aplicación:

Nota

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

El paquete Microsoft.Authentication.WebAssembly.Msal agrega el paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication a la aplicación de forma transitiva.

Compatibilidad con el servicio de autenticación

Esta sección atañe a la aplicación Client de la solución.

Se ha agregado compatibilidad con instancias de HttpClient que incluye tokens de acceso al realizar solicitudes a la aplicación Server.

En el archivo Program:

builder.Services.AddHttpClient("{PROJECT NAME}.ServerAPI", client => 
        client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("{PROJECT NAME}.ServerAPI"));

El marcador de posición {PROJECT NAME} es el nombre del proyecto en la creación de la solución. Por ejemplo, proporcionar un nombre de proyecto de BlazorSample genera un elemento denominado HttpClient de BlazorSample.ServerAPI.

La compatibilidad para autenticar usuarios se registra en el contenedor de servicios con el método de extensión AddMsalAuthentication proporcionado por el paquete Microsoft.Authentication.WebAssembly.Msal. Este método configura los servicios necesarios para que la aplicación interactúe con el proveedor de Identity.

En el archivo Program:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

El método AddMsalAuthentication acepta una devolución de llamada para configurar los parámetros necesarios para autenticar una aplicación. Los valores necesarios para configurar la aplicación se pueden obtener de la configuración de ME-ID de Azure Portal al registrar la aplicación.

Ámbitos de token de acceso

Esta sección atañe a la aplicación Client de la solución.

Los ámbitos de token de acceso predeterminados son una lista de ámbitos de token de acceso con las siguientes características:

  • Están incluidos en la solicitud de inicio de sesión.
  • Se usan para aprovisionar un token de acceso inmediatamente después de la autenticación.

Se pueden agregar ámbitos adicionales según sea necesario en el archivo Program:

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

Especifique ámbitos adicionales con AdditionalScopesToConsent:

options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");

Nota:

AdditionalScopesToConsent no puede aprovisionar permisos de usuario delegado para Microsoft Graph a través de la interfaz de usuario de consentimiento de Microsoft Entra ID cuando un usuario utiliza por primera vez una aplicación registrada en Microsoft Azure. Para obtener más información, consulta Uso de Graph API con ASP.NET Core Blazor WebAssembly.

Ejemplo de ámbito de token de acceso predeterminado:

options.ProviderOptions.DefaultAccessTokenScopes.Add(
    "api://00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");

Para obtener más información, consulta las siguientes secciones del artículo Otros escenarios:

Modo de inicio de sesión

Esta sección atañe a la aplicación Client de la solución.

El marco tiene como valor predeterminado el modo de inicio de sesión emergente y vuelve al modo de inicio de sesión de redireccionamiento si no se puede abrir un elemento emergente. Configura MSAL para usar el modo de inicio de sesión de redireccionamiento mediante el establecimiento de la propiedad LoginMode de MsalProviderOptions en redirect:

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.LoginMode = "redirect";
});

La configuración predeterminada es popup y el valor de cadena no distingue entre mayúsculas y minúsculas.

Archivo Imports

Esta sección atañe a la aplicación Client de la solución.

El espacio de nombres Microsoft.AspNetCore.Components.Authorization está disponible en toda la aplicación a través del archivo _Imports.razor:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}
@using {APPLICATION ASSEMBLY}.Shared

Página de índice

Esta sección atañe a la aplicación Client de la solución.

La página de índice (wwwroot/index.html) incluye un script que define AuthenticationService en JavaScript. AuthenticationService controla los detalles de bajo nivel del protocolo OIDC. La aplicación llama internamente a métodos definidos en el script para realizar las operaciones de autenticación.

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

Componente App

Esta sección atañe a la aplicación Client de la solución.

El componente App (App.razor) es similar al componente App que se encuentra en las aplicaciones Blazor Server:

  • El componente CascadingAuthenticationState administra la exposición de AuthenticationState a rest de la aplicación.
  • El componente AuthorizeRouteView se asegura de que el usuario actual está autorizado para tener acceso a una página determinada o, de lo contrario, representa el componente RedirectToLogin.
  • El componente RedirectToLogin administra el redireccionamiento de usuarios no autorizados a la página de inicio de sesión.

Debido a los cambios del marco en las versiones de ASP.NET Core, el marcado de Razor del componente App (App.razor) no se muestra en esta sección. Para inspeccionar el marcado del componente para una versión determinada, usa cualquiera de los enfoques siguientes:

  • Crea una aplicación aprovisionada para la autenticación a partir de la plantilla de proyecto Blazor WebAssembly predeterminada para la versión de ASP.NET Core que va a usar. Inspecciona el componente App (App.razor) en la aplicación generada.

  • Inspecciona el componente App (App.razor) en el origen de referencia. Selecciona la versión del selector de rama y busca el componente en la carpeta ProjectTemplates del repositorio porque la ubicación del componente App ha cambiado a lo largo de los años.

    Nota:

    Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Componente RedirectToLogin

Esta sección atañe a la aplicación Client de la solución.

El componente RedirectToLogin (RedirectToLogin.razor):

  • Administra el redireccionamiento de usuarios no autorizados a la página de inicio de sesión.
  • La dirección URL actual a la que el usuario intenta tener acceso se conserva para que pueda volver a esa página si la autenticación se realiza correctamente con:

Inspecciona el componente RedirectToLogin en el origen de referencia. La ubicación del componente ha cambiado con el tiempo, usa las herramientas de búsqueda de GitHub para localizar el componente.

Nota:

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Componente LoginDisplay

Esta sección atañe a la aplicación Client de la solución.

El componente LoginDisplay (LoginDisplay.razor) se representa en el componente MainLayout (MainLayout.razor) y administra los siguientes comportamientos:

  • En el caso de los usuarios autenticados:
    • Muestra el nombre de usuario actual.
    • Proporciona un vínculo a la página de perfil de usuario en Identity de ASP.NET Core.
    • Proporciona un botón para cerrar la sesión de la aplicación.
  • En el caso de los usuarios anónimos:
    • Ofrece la opción de registrarse.
    • Ofrece la opción de iniciar sesión.

Debido a los cambios de marco en las versiones de ASP.NET Core, el marcado Razor del componente LoginDisplay no se muestra en esta sección. Para inspeccionar el marcado del componente para una versión determinada, usa cualquiera de los enfoques siguientes:

  • Crea una aplicación aprovisionada para la autenticación a partir de la plantilla de proyecto Blazor WebAssembly predeterminada para la versión de ASP.NET Core que va a usar. Inspecciona el componente LoginDisplay en la aplicación generada.

  • Inspecciona el componente LoginDisplay en el origen de referencia. La ubicación del componente ha cambiado con el tiempo, usa las herramientas de búsqueda de GitHub para localizar el componente. Se usa el contenido con plantilla para Hosted igual a true.

    Nota

    Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Componente Authentication

Esta sección atañe a la aplicación Client de la solución.

La página generada por el componente Authentication (Pages/Authentication.razor) define las rutas necesarias para controlar diferentes fases de autenticación.

El componente RemoteAuthenticatorView:

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code {
    [Parameter]
    public string? Action { get; set; }
}

Nota:

Los tipos de referencia que admiten un valor NULL (NRT) y el análisis estático de estado NULL del compilador de .NET se admiten en ASP.NET Core en .NET 6 o posterior. Antes de la versión de ASP.NET Core en .NET 6, el tipo string aparece sin la designación de tipo NULL (?).

Componente FetchData

Esta sección atañe a la aplicación Client de la solución.

El componente FetchData muestra:

  • Cómo aprovisionar un token de acceso.
  • Cómo usar el token de acceso para llamar a una API de recursos protegidos en la aplicación Server.

La directiva @attribute [Authorize] indica al sistema de autorización de Blazor WebAssembly que el usuario debe estar autorizado para poder visitar este componente. La presencia del atributo en la aplicación Client no impide que se llame a la API en el servidor sin credenciales adecuadas. La aplicación Server debe usar también [Authorize] en los puntos de conexión adecuados para protegerlos correctamente.

IAccessTokenProvider.RequestAccessToken se encarga de solicitar un token de acceso que se puede agregar a la solicitud para llamar a la API. Si el token se almacena en caché o el servicio puede aprovisionar un nuevo token de acceso sin la interacción del usuario, la solicitud de token se realiza correctamente. De lo contrario, se produce un error en la solicitud de token con una AccessTokenNotAvailableException, que se detecta en una instrucción try-catch.

Para obtener el token real que se va a incluir en la solicitud, la aplicación debe comprobar que la solicitud se ha realizado correctamente mediante una llamada a tokenResult.TryGetToken(out var token).

Si la solicitud se ha realizado correctamente, la variable de token se rellena con el token de acceso. La propiedad AccessToken.Value del token expone la cadena literal que se va a incluir en el encabezado de solicitud Authorization.

Si no se ha podido aprovisionar el token sin la interacción del usuario provocando un error en la solicitud:

  • ASP.NET Core en .NET 7 o posterior: la aplicación se dirige a AccessTokenResult.InteractiveRequestUrl usando el valor AccessTokenResult.InteractionOptions especificado para permitir la actualización del token de acceso.
  • ASP.NET Core en .NET 6 o una versión anterior: el resultado del token contiene una URL de redireccionamiento. Al navegar a esta dirección URL, el usuario se dirige a la página de inicio de sesión y vuelve a la página actual si se autentica correctamente.
@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

Uso de un inquilino de Azure Active Directory B2C

Si la aplicación está registrada en un inquilino de Azure Active Directory B2C, como se describe en Tutorial: Creación de un inquilino de Azure Active Directory B2C, pero sigue las instrucciones de este artículo, ME-ID administra el URI del identificador de aplicación de forma diferente.

Para comprobar el tipo de inquilino de un inquilino existente, selecciona el vínculo Administrar inquilinos en la parte superior de la información general de la organización de ME-ID. Examina el valor de la columna Tipo de inquilino de la organización. Esta sección pertenece a las aplicaciones que siguen las instrucciones de este artículo, pero que están registradas en un inquilino de Azure Active Directory B2C.

En lugar del URI del identificador de aplicación que coincide con el formato api://{SERVER API APP CLIENT ID OR CUSTOM VALUE}, el URI del identificador de aplicación tiene el formato https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}. Esta diferencia afecta a las configuraciones de aplicaciones Client y Server:

  • Para la aplicación de API de servidor, establece Audience en el archivo de configuración de la aplicación (appsettings.json) para que coincida con la audiencia de la aplicación (URI de identificador de aplicación) proporcionada por Azure Portal sin la barra diagonal final:

    "Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
    

    Ejemplo:

    "Audience": "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444"
    
  • En el archivo Program de la aplicación Client, establece la audiencia del ámbito (URI de identificador de aplicación) para que coincida con la audiencia de la aplicación de API de servidor:

    options.ProviderOptions.DefaultAccessTokenScopes
        .Add("https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}/{DEFAULT SCOPE}");
    

    En el ámbito anterior, el URI o audiencia del identificador de aplicación es la parte https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE} del valor, que no incluye una barra diagonal final (/) y no incluye el nombre del ámbito ({DEFAULT SCOPE}).

    Ejemplo:

    options.ProviderOptions.DefaultAccessTokenScopes
        .Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");
    

    En el ámbito anterior, el URI o audiencia del identificador de aplicación es la parte https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444 del valor, que no incluye una barra diagonal final (/) y no incluye el nombre del ámbito (API.Access).

Uso de un URI de identificador de aplicación personalizado

Si el URI del identificador de aplicación es un valor personalizado, debes actualizar manualmente el URI de ámbito del token de acceso predeterminado en la aplicación Client y agregar la audiencia a la configuración de ME-ID de la aplicación Server.

Importante

La siguiente configuración no es necesaria cuando se usa el URI de identificador de aplicación predeterminado de api://{SERVER API APP CLIENT ID}.

Ejemplo de URI de identificador de aplicación de urn://custom-app-id-uri y un nombre de ámbito de API.Access:

  • En el archivo Program de la aplicación Client:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "urn://custom-app-id-uri/API.Access");
    
  • En appsettings.json de la aplicación Server, agrega una entrada Audience con solo el URI del identificador de aplicación y ninguna barra diagonal final:

    "Audience": "urn://custom-app-id-uri"
    

Solución de problemas

Registro

Para habilitar el registro de depuración o rastreo para la autenticación de Blazor WebAssembly, consulta la sección Registro de autenticación del lado del cliente del Registro de ASP.NET Core Blazor con el selector de versión del artículo establecido en ASP.NET Core 7.0 o posterior.

Errores comunes

  • Error de configuración de la aplicación o del proveedor de Identity (IP)

    Los errores más comunes se deben a una configuración incorrecta. Estos son algunos ejemplos:

    • En función de los requisitos del escenario, la disponibilidad o no de una autoridad, una instancia, un identificador o dominio de inquilino, un identificador de cliente o un URI de redireccionamiento, o bien que estos no elementos no sean correctos, impide a una aplicación autenticar clientes.
    • Los ámbitos de solicitud incorrectos impiden a los clientes acceder a los puntos de conexión de la API web del servidor.
    • Faltan permisos de la API de servidor o estos son incorrectos, lo cual impide a los clientes acceder a los puntos de conexión de API web.
    • Ejecutar la aplicación en un puerto diferente al configurado en el URI de redirección del registro de aplicación de la IP. Ten en cuenta que no se requiere ningún puerto para Microsoft Entra ID y una aplicación que se ejecute en una dirección de pruebas de desarrollo localhost, pero la configuración del puerto de la aplicación y el puerto en el que se ejecuta la aplicación deben coincidir para las direcciones que no sean localhost.

    En las secciones de configuración de la guía de este artículo se muestran ejemplos de la configuración correcta. Consulta detenidamente cada sección del artículo en busca de la configuración de la aplicación y la de IP.

    Si la configuración parece correcta:

    • Analiza los registros de la aplicación.

    • Examina el tráfico de red entre la aplicación cliente y la de servidor, o la dirección IP con las herramientas de desarrollo del explorador. A menudo, la aplicación de servidor o la dirección IP devuelve al cliente un mensaje de error exacto o un mensaje con una pista sobre la causa del problema. En los siguientes artículos encontrarás instrucciones sobre las herramientas de desarrollo:

    • Para las versiones de Blazor en las que se utiliza un JSON Web Token (JWT), descodifica el contenido del token utilizado para autenticar a un cliente o acceder a una API web del servidor, dependiendo de dónde se esté produciendo el problema. Para obtener más información, vea Inspección del contenido de un JSON Web Token (JWT).

    El equipo de documentación responde a los comentarios y los errores en los artículos (abre una incidencia en la sección de comentarios de esta página), pero no puede proporcionar soporte técnico para el producto. Existen varios foros de soporte técnico públicos que ayudan a solucionar los problemas de una aplicación. Se recomienda lo siguiente:

    Microsoft no posee ni controla ninguno de los foros anteriores.

    Respecto a los informes de errores del marco que no son de seguridad ni confidenciales, o que no se pueden reproducir, abre una incidencia con la unidad de producto ASP.NET Core. No abras una incidencia con la unidad de producto hasta que hayas investigado exhaustivamente su causa y no puedas resolverlo por tu cuenta o con la ayuda de la comunidad en un foro de soporte técnico público. La unidad de producto no puede solucionar problemas de aplicaciones individuales cuyo funcionamiento se haya interrumpido debido a errores de configuración o casos de uso sencillos que involucren servicios de terceros. Si un informe es confidencial o delicado por naturaleza o describe un posible error de seguridad en el producto que los ciberdelincuentes puedan aprovechar, consulta Informes de problemas de seguridad y errores (repositorio de GitHub dotnet/aspnetcore).

  • Cliente no autorizado para ME-ID

    Información: Error de autorización de Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]. No se cumplen estos requisitos: DenyAnonymousAuthorizationRequirement: se requiere un usuario autenticado.

    Error de devolución de llamada de inicio de sesión de ME-ID:

    • Error: unauthorized_client
    • Descripción: AADB2C90058: The provided application is not configured to allow public clients.

    Para resolver el error:

    1. En Azure Portal, accede al manifiesto de la aplicación.
    2. Establece el atributo allowPublicClient en null o true.

Cookies y datos de sitios

Las cookies y los datos de sitios pueden persistir durante las actualizaciones de la aplicación e interferir con las pruebas y la solución de problemas. Borra los elementos siguientes al realizar cambios en el código de la aplicación, cambios en la cuenta de usuario con el proveedor o cuando el proveedor modifique la configuración de la aplicación:

  • Cookies de inicio de sesión de usuario
  • Cookies de aplicación
  • Datos de sitios almacenados y en caché

El enfoque siguiente sirve para evitar que las cookies persistentes y los datos de sitios interfieran con las pruebas y la solución de problemas:

  • Configuración de un explorador
    • Usa un explorador para las pruebas, y configúralo para que elimine todas las cookies y los datos del sitio cada vez que se cierre.
    • Asegúrate de que el explorador se cierra manualmente o mediante el IDE siempre que se produzca cualquier cambio en la aplicación, el usuario de prueba o la configuración del proveedor.
  • Usa un comando personalizado para abrir un explorador en el modo incógnito o privado en Visual Studio:
    • Abre el cuadro de diálogo Examinar con mediante el botón Ejecutar de Visual Studio.
    • Selecciona el botón Agregar.
    • Proporciona la ruta de acceso al explorador en el campo Programa. Las siguientes rutas de acceso del archivo ejecutable son ubicaciones de instalación típicas para Windows 10. Si el explorador está instalado en una ubicación diferente o no usa Windows 10, proporciona la ruta de acceso al archivo ejecutable del explorador.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • En el campo Argumentos, proporciona la opción de línea de comandos que utiliza el explorador para abrirse en el modo incógnito o privado. Algunos exploradores requieren la dirección URL de la aplicación.
      • Microsoft Edge: Usa -inprivate.
      • Google Chrome: usa --incognito --new-window {URL}, donde el marcador de posición {URL} es la dirección URL que se va a abrir (por ejemplo, https://localhost:5001).
      • Mozilla Firefox: usa -private -url {URL}, donde el marcador de posición {URL} es la dirección URL que se va a abrir (por ejemplo, https://localhost:5001).
    • Proporciona un nombre en el campo Nombre descriptivo. Por ejemplo: Firefox Auth Testing.
    • Selecciona el botón Aceptar.
    • Para evitar tener que seleccionar el perfil de explorador para cada iteración de pruebas con una aplicación, establece el perfil como predeterminado con el botón Establecer como predeterminado.
    • Asegúrate de que el explorador se cierra mediante el IDE siempre que se produzca cualquier cambio en la aplicación, el usuario de prueba o la configuración del proveedor.

Actualizaciones de aplicaciones

Una aplicación en funcionamiento deja de ejecutarse inmediatamente después de actualizar el SDK de .NET Core en la máquina de desarrollo o de cambiar las versiones del paquete en la aplicación. En algunos casos, los paquetes incoherentes pueden interrumpir una aplicación al realizar actualizaciones importantes. La mayoría de estos problemas puede corregirse siguiendo estas instrucciones:

  1. Borra las memorias caché del paquete NuGet del sistema local ejecutando dotnet nuget locals all --clear desde un shell de comandos.
  2. Elimina las carpetas bin y obj del proyecto.
  3. Restaura el proyecto y vuelve a compilarlo.
  4. Elimina todos los archivos de la carpeta de implementación del servidor antes de volver a implementar la aplicación.

Nota

No se pueden usar versiones de paquetes que no sean compatibles con la plataforma de destino de la aplicación. Para obtener información sobre un paquete, usa la galería de NuGet o el explorador de paquetes FuGet.

Ejecuta la aplicación Server

Al realizar pruebas y solucionar problemas de una soluciónBlazor WebAssembly hospedada, asegúrate de ejecutar la aplicación desde el proyecto Server.

Inspección del usuario

El siguiente componente User se puede usar directamente en las aplicaciones, o bien servir como base para una mayor personalización.

User.razor:

@page "/user"
@attribute [Authorize]
@using System.Text.Json
@using System.Security.Claims
@inject IAccessTokenProvider AuthorizationService

<h1>@AuthenticatedUser?.Identity?.Name</h1>

<h2>Claims</h2>

@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
    <p class="claim">@(claim.Type): @claim.Value</p>
}

<h2>Access token</h2>

<p id="access-token">@AccessToken?.Value</p>

<h2>Access token claims</h2>

@foreach (var claim in GetAccessTokenClaims())
{
    <p>@(claim.Key): @claim.Value.ToString()</p>
}

@if (AccessToken != null)
{
    <h2>Access token expires</h2>

    <p>Current time: <span id="current-time">@DateTimeOffset.Now</span></p>
    <p id="access-token-expires">@AccessToken.Expires</p>

    <h2>Access token granted scopes (as reported by the API)</h2>

    @foreach (var scope in AccessToken.GrantedScopes)
    {
        <p>Scope: @scope</p>
    }
}

@code {
    [CascadingParameter]
    private Task<AuthenticationState> AuthenticationState { get; set; }

    public ClaimsPrincipal AuthenticatedUser { get; set; }
    public AccessToken AccessToken { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        var state = await AuthenticationState;
        var accessTokenResult = await AuthorizationService.RequestAccessToken();

        if (!accessTokenResult.TryGetToken(out var token))
        {
            throw new InvalidOperationException(
                "Failed to provision the access token.");
        }

        AccessToken = token;

        AuthenticatedUser = state.User;
    }

    protected IDictionary<string, object> GetAccessTokenClaims()
    {
        if (AccessToken == null)
        {
            return new Dictionary<string, object>();
        }

        // header.payload.signature
        var payload = AccessToken.Value.Split(".")[1];
        var base64Payload = payload.Replace('-', '+').Replace('_', '/')
            .PadRight(payload.Length + (4 - payload.Length % 4) % 4, '=');

        return JsonSerializer.Deserialize<IDictionary<string, object>>(
            Convert.FromBase64String(base64Payload));
    }
}

Inspección del contenido de un JSON Web Token (JWT)

Para descodificar un JSON Web Token (JWT), usa la herramienta jwt.ms de Microsoft. Los valores de la interfaz de usuario nunca salen del explorador.

Ejemplo de JWT codificado (se muestra una versión abreviada):

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q

Ejemplo de JWT descodificado por la herramienta para una aplicación que se autentica en Azure AAD B2C:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
  "exp": 1610059429,
  "nbf": 1610055829,
  "ver": "1.0",
  "iss": "https://mysiteb2c.b2clogin.com/11112222-bbbb-3333-cccc-4444dddd5555/v2.0/",
  "sub": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
  "aud": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "nonce": "bbbb0000-cccc-1111-dddd-2222eeee3333",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

Recursos adicionales