Protección de una aplicación hospedada Blazor WebAssembly de ASP.NET Core con Azure Active Directory

En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa Azure Active Directory (AAD) para la autenticación.

Nota

En el caso de las aplicaciones Blazor WebAssembly creadas en Visual Studio que están configuradas para admitir cuentas en un directorio organizativo de AAD con la plataforma de Identity de Microsoft, use la versión 16.10 o posterior de Visual Studio para crear la aplicación con la configuración correcta de Azure. Si usa una versión de Visual Studio anterior a la 16.10, debe actualizar manualmente la configuración de la aplicación por cada sección de este artículo después de generar la aplicación.

Registro de aplicaciones en AAD y creación de una solución

Creación de un inquilino

Siga las instrucciones que encontrará en Inicio rápido: Configuración de un inquilino para crear un inquilino en AAD.

Registro de una aplicación de API de servidor

Registre una aplicación de AAD para la aplicación de API de servidor:

  1. Vaya a Azure Active Directory 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 Server AAD).
  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 redirección en este escenario, así que deje la lista desplegable establecida en Web y no especifique ningún URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre la siguiente información:

  • Identificador de aplicación (cliente) de la aplicación de API de servidor; por ejemplo, 41451fa7-82d9-4673-8fa5-69eff5a761fd.
  • Identificador de directorio (inquilino); por ejemplo, e86c78e2-8bb4-4c41-aefd-918e0565a45e.
  • Dominio de AAD Principal/Publicador/Inquilino (por ejemplo, contoso.onmicrosoft.com): El dominio está disponible como Dominio del publicador en la hoja Personalización de marca de Azure Portal de la aplicación registrada.

En Permisos de API, quite el permiso Microsoft Graph > User.Read, ya que la aplicación no necesita el inicio de sesión ni el acceso de perfil de usuario.

En Exponer una API:

  1. Seleccione Agregar un ámbito.
  2. Seleccione Guardar y continuar.
  3. Indique un Nombre de ámbito (por ejemplo, API.Access).
  4. Indique un Nombre para mostrar del consentimiento del administrador (por ejemplo, Access API).
  5. Proporcione una Descripción del consentimiento del administrador (por ejemplo, Allows the app to access server app API endpoints.).
  6. Confirme que Estado está establecido en Habilitado.
  7. Seleccione la opción Agregar un ámbito.

Registre la siguiente información:

  • URI del identificador de aplicación (por ejemplo, api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd o el valor personalizado que haya proporcionado)
  • Nombre del ámbito (por ejemplo, API.Access)

Registrar una aplicación cliente

Registre una aplicación de AAD para la aplicación cliente:

  1. Vaya a Azure Active Directory 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 AAD).
  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 redirección en Aplicación de página única y proporcione el siguiente URI de redirección: https://localhost:{PORT}/authentication/login-callback. El puerto predeterminado de una aplicación que se ejecuta en Kestrel es 5001. Si la aplicación se ejecuta en otro puerto de Kestrel, use el puerto de la aplicación. En el caso de IIS Express, el puerto generado aleatoriamente para la aplicación se encuentra en las propiedades de la aplicación Server , en el panel Depurar. Dado que la aplicación no existe en este momento y no conocemos el puerto de IIS Express, vuelva a este paso después de crear la aplicación y actualice el URI de redirección. En la sección Creación de la aplicación aparece un comentario para recordar a los usuarios de IIS Express que actualicen el URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre el identificador de la aplicación Client (cliente); por ejemplo, 4369008b-21fa-427c-abaa-9b53bf58e538.

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

  1. Confirme que el URI de redirección de https://localhost:{PORT}/authentication/login-callback está presente.
  2. En Concesión implícita, asegúrese de que las casillas Tokens de acceso y Tokens de id. no están seleccionadas.
  3. Los valores predeterminados restantes de la aplicación son aceptables en esta experiencia.
  4. Seleccione el botón Guardar.

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 AAD).
  4. Abra la lista API.
  5. Habilite el acceso a la API (por ejemplo, API.Access).
  6. Seleccione Agregar permisos.
  7. Seleccione el botón Conceder consentimiento de administrador para {NOMBRE DE INQUILINO} . Seleccione para confirmar la acción.

Creación de la aplicación

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}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} --tenant-id "{TENANT ID}"

Advertencia

Evite usar guiones (-) en el nombre de la aplicación {APP 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, consulte 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
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Identificador de aplicación (cliente) para la aplicación Client 4369008b-21fa-427c-abaa-9b53bf58e538
{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 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} URI de Id. de aplicación† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{TENANT DOMAIN} Dominio Principal/Publicador/Inquilino contoso.onmicrosoft.com
{TENANT ID} Id. de directorio (inquilino) e86c78e2-8bb4-4c41-aefd-918e0565a45e

†La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al proporcionar el URI de identificador de aplicación para el marcador de posición {SERVER API APP ID URI} y si el esquema es api://, quite el esquema (api://) del argumento, como se muestra en el valor de ejemplo de la tabla anterior. Si el URI de identificador de aplicación es un valor personalizado o tiene algún otro esquema (por ejemplo, https:// para un dominio de publicador no comprobado similar a https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd), debe actualizar manualmente el URI del ámbito predeterminado y quitar el esquema api:// después de que la plantilla cree la aplicación Client . Para obtener más información, consulte la nota de la sección Ámbitos de token de acceso. La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

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 de la aplicación. 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).

Nota

Es posible que se requiera un cambio de configuración al usar un inquilino de Azure con un dominio de publicador no comprobado, lo cual se describe en la sección Configuración de la aplicación.

Nota

En Azure Portal, el valor de configuración de plataforma de la aplicación Client URI de redirección de la aplicación se establece en el puerto 5001 en el caso de las aplicaciones que se ejecutan en el servidor Kestrel con la configuración predeterminada.

Si la aplicación Client se ejecuta en un puerto de IIS Express aleatorio, el puerto de la aplicación se encuentra en las propiedades de la aplicación de API de servidor, en el panel Depurar.

Si el puerto no se configuró anteriormente con el puerto conocido de la aplicación Client , vuelva al registro de la aplicación Client en Azure Portal y actualice el URI de redirección con el puerto correcto.

Configuración de la aplicación Server

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

Paquete de autenticación

La compatibilidad con la autenticación y autorización de llamadas realizadas a las API web de ASP.NET Core con Microsoft Identity Platform se proporciona mediante el paquete Microsoft.Identity.Web:

<PackageReference Include="Microsoft.Identity.Web" Version="{VERSION}" />

El marcador de posición {VERSION} representa la última versión estable del paquete que coincide con la versión del marco compartida de la aplicación y se puede encontrar en el historial de versiones del paquete en la galería de NuGet.

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 de forma predeterminada. 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

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 método AddMicrosoftIdentityWebApi configura servicios para proteger la API web con Microsoft Identity Platform 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.

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

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();

User.Identity.Name

De manera predeterminada, 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, 2d64b3da-d9d5-42c6-9352-53d8df33d770@contoso.onmicrosoft.com).

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

Configuración de la aplicación

El archivo appsettings.json contiene las opciones para configurar el controlador de portador JWT que se usa para validar los tokens de acceso:

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

Ejemplo:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "contoso.onmicrosoft.com",
    "TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "CallbackPath": "/signin-oidc"
  }
}

Cuando se trabaja con una API de servidor registrada en AAD y el registro de AAD de la aplicación se encuentra en un inquilino que se basa en un dominio de publicador no comprobado, el URI del identificador de la aplicación de la API del servidor no es api://{SERVER API APP CLIENT ID OR CUSTOM VALUE} sino que, en su lugar, tiene el formato https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}. Si ese es el caso, el ámbito del token de acceso predeterminado en Program.cs de la aplicación Client es similar al siguiente:

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

Para configurar la aplicación de API de servidor para una audiencia coincidente, establezca el valor Audience en el archivo de configuración de la aplicación de API Server (appsettings.json) para que coincida con la audiencia de la aplicación proporcionada por Azure Portal:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "ValidateAuthority": true,
    "Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
  }
}

En la configuración anterior, el final del valor Audience no incluye el ámbito predeterminado /{DEFAULT SCOPE}.

Ejemplo:

En Program.cs de la aplicación Client :

options.ProviderOptions.DefaultAccessTokenScopes
    .Add("https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");

Configure el archivo de configuración de la aplicación de API Server (appsettings.json) con una audiencia correspondiente (Audience):

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "ValidateAuthority": true,
    "Audience": "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd"
  }
}

En el ejemplo anterior, el final del valor Audience no incluye el ámbito predeterminado /API.Access.

Controlador WeatherForecast

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]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Configuración de la aplicación Client

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

Paquete de autenticació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 agrega autenticación a una aplicación, agregue el paquete manualmente al archivo de proyecto de la aplicación:

<PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" 
  Version="{VERSION}" />

En el caso del marcador de posición {VERSION}, la versión estable más reciente del paquete que coincide con la versión del marco compartida de la aplicación se puede encontrar en el historial de versiones 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

Se ha agregado compatibilidad con instancias de HttpClient que incluye tokens de acceso al realizar solicitudes al proyecto de servidor.

Program.cs:

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

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

El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).

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.

Program.cs:

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 AAD de Azure Portal al registrar la aplicació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": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": true
  }
}

Ámbitos de token de acceso

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

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

Todos los ámbitos deben pertenecer a la misma aplicación según las reglas de Azure Active Directory. En caso necesario, se pueden agregar más ámbitos para otras aplicaciones de API adicionales:

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

Nota

La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al generar una aplicación a partir de la plantilla de proyecto Blazor, confirme que el valor del ámbito de token de acceso predeterminado usa el valor de URI de identificador de aplicación personalizado correcto que proporcionó en Azure Portal o un valor con uno de los siguientes formatos:

  • Cuando el dominio del publicador del directorio es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor de un esquema doble (api://api://...). Si hay un esquema doble, quite el primer esquema api:// del valor.

  • Cuando el dominio del publicador del directorio no es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor para ver si hay un esquema api:// adicional (api://https://contoso.onmicrosoft.com/...). Si hay un esquema api:// adicional, quite el esquema api:// del valor.

La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

Especifique ámbitos adicionales con AdditionalScopesToConsent:

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

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

Modo de inicio de sesió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. Configure 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 popupy el valor de cadena no distingue entre mayúsculas y minúsculas.

Archivo Imports

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}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

Página de índice

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

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 al resto 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, use cualquiera de los enfoques siguientes:

  • Cree 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. Inspeccione el componente App (App.razor) en la aplicación generada.

  • Inspeccione el componente App (App.razor) en el origen de referencia.

    Nota

    Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.

Componente RedirectToLogin

El componente RedirectToLogin (Shared/RedirectToLogin.razor):

  • Administra el redireccionamiento de usuarios no autorizados a la página de inicio de sesión.
  • Conserva la dirección URL actual a la que el usuario intenta tener acceso para que pueda volver a esa página si la autenticación se realiza correctamente.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

Componente LoginDisplay

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

  • En el caso de los usuarios autenticados:
    • Muestra el nombre de usuario actual.
    • Proporciona un botón para cerrar la sesión de la aplicación.
  • En el caso de los usuarios anónimos, ofrece la posibilidad de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Componente Authentication

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; }
}

Componente FetchData

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 se produjo un error en la solicitud porque no se pudo aprovisionar el token sin la interacción del usuario, el resultado del token contiene una dirección 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();
        }
    }
}

Ejecutar la aplicación

Ejecute la aplicación desde el proyecto de servidor. Al usar Visual Studio, puede hacer lo siguiente:

  • Establezca la lista desplegable Proyectos de inicio de la barra de herramientas en la aplicación de API de servidor y seleccione el botón Ejecutar.
  • Seleccione el proyecto de servidor en el Explorador de soluciones y seleccione el botón Ejecutar de la barra de herramientas, o bien inicie la aplicación desde el menú Depurar.

Solución de problemas

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.
    • Un ámbito de token de acceso incorrecto impide 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 otro puerto que no sea el configurado en el URI de redireccionamiento del registro de la aplicación del proveedor de Identity.

    En las secciones de configuración de la guía de este artículo se muestran ejemplos de la configuración correcta. Compruebe 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:

    • Analice los registros de la aplicación.

    • Examine 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á instrucciones sobre las herramientas de desarrollo:

    • Descodifique el contenido de un JSON Web Token (JWT) usado para autenticar un cliente o acceder a una API web del servidor, según dónde esté 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 (abra 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:

    Respecto a los informes de errores del marco que no son de seguridad ni confidenciales, o que no se pueden reproducir, abra una incidencia con la unidad de producto ASP.NET Core. No abra una incidencia con la unidad de producto hasta que haya investigado exhaustivamente su causa y no pueda resolverlo por su 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 por naturaleza o describe un posible error de seguridad en el producto que los atacantes pueden aprovechar, vea Informes de problemas de seguridad y errores (repositorio de GitHub dotnet/aspnetcore).

  • Cliente no autorizado para AAD

    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 AAD:

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

    Para resolver el error:

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

Cookies y datos del sitio

Las Cookies y los datos del sitio pueden persistir entre las actualizaciones de la aplicación e interferir con las pruebas y la solución de problemas. Borre 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 del usuario
  • cookies de aplicaciones
  • Datos de sitios almacenados y en caché

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

  • Configuración de un explorador
    • Use un explorador para las pruebas, y configúrelo para que elimine todas las cookies y los datos del sitio cada vez que se cierre.
    • Asegúrese 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.
  • Use un comando personalizado para abrir un explorador en el modo incógnito o privado en Visual Studio:
    • Abra el cuadro de diálogo Examinar con mediante el botón Ejecutar de Visual Studio.
    • Seleccione el botón Agregar.
    • Proporcione 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, proporcione 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, proporcione 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: Use -inprivate.
      • Google Chrome: Use --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: Use -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).
    • Proporcione un nombre en el campo Nombre descriptivo. Por ejemplo: Firefox Auth Testing.
    • Seleccione el botón Aceptar.
    • Para evitar tener que seleccionar el perfil de explorador para cada iteración de pruebas con una aplicación, establezca el perfil como predeterminado con el botón Establecer como predeterminado.
    • Asegúrese 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. Borre las memorias caché del paquete NuGet del sistema local ejecutando dotnet nuget locals all --clear desde un shell de comandos.
  2. Elimine las carpetas bin y obj del proyecto.
  3. Restaure el proyecto y vuelva a compilarlo.
  4. Elimine 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, use la galería de NuGet o el explorador de paquetes FuGet.

Ejecución de la aplicación Server

Al realizar pruebas y solucionar problemas de una solución Blazor hospedada, asegúrese ejecutarla desde el proyecto Server . Por ejemplo, en Visual Studio, confirme que el proyecto Server está resaltado en el Explorador de soluciones antes de iniciar la aplicación con cualquiera de los métodos siguientes:

  • Haga clic en el botón Ejecutar.
  • En el menú, seleccione Depurar > Iniciar depuración.
  • Presione F5.

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

Para descodificar un JSON Web Token (JWT), use 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/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

Recursos adicionales

En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa Azure Active Directory (AAD) para la autenticación.

Nota

En el caso de las aplicaciones Blazor WebAssembly creadas en Visual Studio que están configuradas para admitir cuentas en un directorio organizativo de AAD con la plataforma de Identity de Microsoft, use la versión 16.10 o posterior de Visual Studio para crear la aplicación con la configuración correcta de Azure. Si usa una versión de Visual Studio anterior a la 16.10, debe actualizar manualmente la configuración de la aplicación por cada sección de este artículo después de generar la aplicación.

Registro de aplicaciones en AAD y creación de una solución

Creación de un inquilino

Siga las instrucciones que encontrará en Inicio rápido: Configuración de un inquilino para crear un inquilino en AAD.

Registro de una aplicación de API de servidor

Registre una aplicación de AAD para la aplicación de API de servidor:

  1. Vaya a Azure Active Directory 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 Server AAD).
  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 redirección en este escenario, así que deje la lista desplegable establecida en Web y no especifique ningún URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre la siguiente información:

  • Identificador de aplicación (cliente) de la aplicación de API de servidor; por ejemplo, 41451fa7-82d9-4673-8fa5-69eff5a761fd.
  • Identificador de directorio (inquilino); por ejemplo, e86c78e2-8bb4-4c41-aefd-918e0565a45e.
  • Dominio de AAD Principal/Publicador/Inquilino (por ejemplo, contoso.onmicrosoft.com): El dominio está disponible como Dominio del publicador en la hoja Personalización de marca de Azure Portal de la aplicación registrada.

En Permisos de API, quite el permiso Microsoft Graph > User.Read, ya que la aplicación no necesita el inicio de sesión ni el acceso de perfil de usuario.

En Exponer una API:

  1. Seleccione Agregar un ámbito.
  2. Seleccione Guardar y continuar.
  3. Indique un Nombre de ámbito (por ejemplo, API.Access).
  4. Indique un Nombre para mostrar del consentimiento del administrador (por ejemplo, Access API).
  5. Proporcione una Descripción del consentimiento del administrador (por ejemplo, Allows the app to access server app API endpoints.).
  6. Confirme que Estado está establecido en Habilitado.
  7. Seleccione la opción Agregar un ámbito.

Registre la siguiente información:

  • URI del identificador de aplicación (por ejemplo, api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd o el valor personalizado que haya proporcionado)
  • Nombre del ámbito (por ejemplo, API.Access)

Registrar una aplicación cliente

Registre una aplicación de AAD para la aplicación cliente:

  1. Vaya a Azure Active Directory 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 AAD).
  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 redirección en Aplicación de página única y proporcione el siguiente URI de redirección: https://localhost:{PORT}/authentication/login-callback. El puerto predeterminado de una aplicación que se ejecuta en Kestrel es 5001. Si la aplicación se ejecuta en otro puerto de Kestrel, use el puerto de la aplicación. En el caso de IIS Express, el puerto generado aleatoriamente para la aplicación se encuentra en las propiedades de la aplicación Server , en el panel Depurar. Dado que la aplicación no existe en este momento y no conocemos el puerto de IIS Express, vuelva a este paso después de crear la aplicación y actualice el URI de redirección. En la sección Creación de la aplicación aparece un comentario para recordar a los usuarios de IIS Express que actualicen el URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre el identificador de la aplicación Client (cliente); por ejemplo, 4369008b-21fa-427c-abaa-9b53bf58e538.

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

  1. Confirme que el URI de redirección de https://localhost:{PORT}/authentication/login-callback está presente.
  2. En Concesión implícita, asegúrese de que las casillas Tokens de acceso y Tokens de id. no están seleccionadas.
  3. Los valores predeterminados restantes de la aplicación son aceptables en esta experiencia.
  4. Seleccione el botón Guardar.

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 AAD).
  4. Abra la lista API.
  5. Habilite el acceso a la API (por ejemplo, API.Access).
  6. Seleccione Agregar permisos.
  7. Seleccione el botón Conceder consentimiento de administrador para {NOMBRE DE INQUILINO} . Seleccione para confirmar la acción.

Creación de la aplicación

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}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} --tenant-id "{TENANT ID}"

Advertencia

Evite usar guiones (-) en el nombre de la aplicación {APP 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, consulte 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
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Identificador de aplicación (cliente) para la aplicación Client 4369008b-21fa-427c-abaa-9b53bf58e538
{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 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} URI de Id. de aplicación† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{TENANT DOMAIN} Dominio Principal/Publicador/Inquilino contoso.onmicrosoft.com
{TENANT ID} Id. de directorio (inquilino) e86c78e2-8bb4-4c41-aefd-918e0565a45e

†La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al proporcionar el URI de identificador de aplicación para el marcador de posición {SERVER API APP ID URI} y si el esquema es api://, quite el esquema (api://) del argumento, como se muestra en el valor de ejemplo de la tabla anterior. Si el URI de identificador de aplicación es un valor personalizado o tiene algún otro esquema (por ejemplo, https:// para un dominio de publicador no comprobado similar a https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd), debe actualizar manualmente el URI del ámbito predeterminado y quitar el esquema api:// después de que la plantilla cree la aplicación Client . Para obtener más información, consulte la nota de la sección Ámbitos de token de acceso. La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

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 de la aplicación. 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).

Nota

Es posible que se requiera un cambio de configuración al usar un inquilino de Azure con un dominio de publicador no comprobado, lo cual se describe en la sección Configuración de la aplicación.

Nota

En Azure Portal, el valor de configuración de plataforma de la aplicación Client URI de redirección de la aplicación se establece en el puerto 5001 en el caso de las aplicaciones que se ejecutan en el servidor Kestrel con la configuración predeterminada.

Si la aplicación Client se ejecuta en un puerto de IIS Express aleatorio, el puerto de la aplicación se encuentra en las propiedades de la aplicación de API de servidor, en el panel Depurar.

Si el puerto no se configuró anteriormente con el puerto conocido de la aplicación Client , vuelva al registro de la aplicación Client en Azure Portal y actualice el URI de redirección con el puerto correcto.

Configuración de la aplicación Server

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

Paquete de autenticación

La compatibilidad con la autenticación y autorización de llamadas realizadas a las API web de ASP.NET Core con Microsoft Identity Platform se proporciona mediante el paquete Microsoft.Identity.Web:

<PackageReference Include="Microsoft.Identity.Web" Version="{VERSION}" />

El marcador de posición {VERSION} representa la última versión estable del paquete que coincide con la versión del marco compartida de la aplicación y se puede encontrar en el historial de versiones del paquete en la galería de NuGet.

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 de forma predeterminada. 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

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 método AddMicrosoftIdentityWebApi configura servicios para proteger la API web con Microsoft Identity Platform 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.

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

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();

User.Identity.Name

De manera predeterminada, 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, 2d64b3da-d9d5-42c6-9352-53d8df33d770@contoso.onmicrosoft.com).

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

Configuración de la aplicación

El archivo appsettings.json contiene las opciones para configurar el controlador de portador JWT que se usa para validar los tokens de acceso:

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

Ejemplo:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "contoso.onmicrosoft.com",
    "TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "CallbackPath": "/signin-oidc"
  }
}

Cuando se trabaja con una API de servidor registrada en AAD y el registro de AAD de la aplicación se encuentra en un inquilino que se basa en un dominio de publicador no comprobado, el URI del identificador de la aplicación de la API del servidor no es api://{SERVER API APP CLIENT ID OR CUSTOM VALUE} sino que, en su lugar, tiene el formato https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}. Si ese es el caso, el ámbito del token de acceso predeterminado en Program.cs de la aplicación Client es similar al siguiente:

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

Para configurar la aplicación de API de servidor para una audiencia coincidente, establezca el valor Audience en el archivo de configuración de la aplicación de API Server (appsettings.json) para que coincida con la audiencia de la aplicación proporcionada por Azure Portal:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "ValidateAuthority": true,
    "Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
  }
}

En la configuración anterior, el final del valor Audience no incluye el ámbito predeterminado /{DEFAULT SCOPE}.

Ejemplo:

En Program.cs de la aplicación Client :

options.ProviderOptions.DefaultAccessTokenScopes
    .Add("https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");

Configure el archivo de configuración de la aplicación de API Server (appsettings.json) con una audiencia correspondiente (Audience):

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "ValidateAuthority": true,
    "Audience": "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd"
  }
}

En el ejemplo anterior, el final del valor Audience no incluye el ámbito predeterminado /API.Access.

Controlador WeatherForecast

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]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Configuración de la aplicación Client

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

Paquete de autenticació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 agrega autenticación a una aplicación, agregue el paquete manualmente al archivo de proyecto de la aplicación:

<PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" 
  Version="{VERSION}" />

En el caso del marcador de posición {VERSION}, la versión estable más reciente del paquete que coincide con la versión del marco compartida de la aplicación se puede encontrar en el historial de versiones 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

Se ha agregado compatibilidad con instancias de HttpClient que incluye tokens de acceso al realizar solicitudes al proyecto de servidor.

Program.cs:

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

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

El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).

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.

Program.cs:

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 AAD de Azure Portal al registrar la aplicació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": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": true
  }
}

Ámbitos de token de acceso

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

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

Todos los ámbitos deben pertenecer a la misma aplicación según las reglas de Azure Active Directory. En caso necesario, se pueden agregar más ámbitos para otras aplicaciones de API adicionales:

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

Nota

La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al generar una aplicación a partir de la plantilla de proyecto Blazor, confirme que el valor del ámbito de token de acceso predeterminado usa el valor de URI de identificador de aplicación personalizado correcto que proporcionó en Azure Portal o un valor con uno de los siguientes formatos:

  • Cuando el dominio del publicador del directorio es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor de un esquema doble (api://api://...). Si hay un esquema doble, quite el primer esquema api:// del valor.

  • Cuando el dominio del publicador del directorio no es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor para ver si hay un esquema api:// adicional (api://https://contoso.onmicrosoft.com/...). Si hay un esquema api:// adicional, quite el esquema api:// del valor.

La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

Especifique ámbitos adicionales con AdditionalScopesToConsent:

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

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

Modo de inicio de sesió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. Configure 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 popupy el valor de cadena no distingue entre mayúsculas y minúsculas.

Archivo Imports

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}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

Página de índice

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

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 al resto 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, use cualquiera de los enfoques siguientes:

  • Cree 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. Inspeccione el componente App (App.razor) en la aplicación generada.

  • Inspeccione el componente App (App.razor) en el origen de referencia.

    Nota

    Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.

Componente RedirectToLogin

El componente RedirectToLogin (Shared/RedirectToLogin.razor):

  • Administra el redireccionamiento de usuarios no autorizados a la página de inicio de sesión.
  • Conserva la dirección URL actual a la que el usuario intenta tener acceso para que pueda volver a esa página si la autenticación se realiza correctamente.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

Componente LoginDisplay

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

  • En el caso de los usuarios autenticados:
    • Muestra el nombre de usuario actual.
    • Proporciona un botón para cerrar la sesión de la aplicación.
  • En el caso de los usuarios anónimos, ofrece la posibilidad de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Componente Authentication

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; }
}

Componente FetchData

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 se produjo un error en la solicitud porque no se pudo aprovisionar el token sin la interacción del usuario, el resultado del token contiene una dirección 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();
        }
    }
}

Ejecutar la aplicación

Ejecute la aplicación desde el proyecto de servidor. Al usar Visual Studio, puede hacer lo siguiente:

  • Establezca la lista desplegable Proyectos de inicio de la barra de herramientas en la aplicación de API de servidor y seleccione el botón Ejecutar.
  • Seleccione el proyecto de servidor en el Explorador de soluciones y seleccione el botón Ejecutar de la barra de herramientas, o bien inicie la aplicación desde el menú Depurar.

Solución de problemas

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.
    • Un ámbito de token de acceso incorrecto impide 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 otro puerto que no sea el configurado en el URI de redireccionamiento del registro de la aplicación del proveedor de Identity.

    En las secciones de configuración de la guía de este artículo se muestran ejemplos de la configuración correcta. Compruebe 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:

    • Analice los registros de la aplicación.

    • Examine 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á instrucciones sobre las herramientas de desarrollo:

    • Descodifique el contenido de un JSON Web Token (JWT) usado para autenticar un cliente o acceder a una API web del servidor, según dónde esté 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 (abra 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:

    Respecto a los informes de errores del marco que no son de seguridad ni confidenciales, o que no se pueden reproducir, abra una incidencia con la unidad de producto ASP.NET Core. No abra una incidencia con la unidad de producto hasta que haya investigado exhaustivamente su causa y no pueda resolverlo por su 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 por naturaleza o describe un posible error de seguridad en el producto que los atacantes pueden aprovechar, vea Informes de problemas de seguridad y errores (repositorio de GitHub dotnet/aspnetcore).

  • Cliente no autorizado para AAD

    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 AAD:

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

    Para resolver el error:

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

Cookies y datos del sitio

Las Cookies y los datos del sitio pueden persistir entre las actualizaciones de la aplicación e interferir con las pruebas y la solución de problemas. Borre 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 del usuario
  • cookies de aplicaciones
  • Datos de sitios almacenados y en caché

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

  • Configuración de un explorador
    • Use un explorador para las pruebas, y configúrelo para que elimine todas las cookies y los datos del sitio cada vez que se cierre.
    • Asegúrese 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.
  • Use un comando personalizado para abrir un explorador en el modo incógnito o privado en Visual Studio:
    • Abra el cuadro de diálogo Examinar con mediante el botón Ejecutar de Visual Studio.
    • Seleccione el botón Agregar.
    • Proporcione 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, proporcione 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, proporcione 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: Use -inprivate.
      • Google Chrome: Use --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: Use -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).
    • Proporcione un nombre en el campo Nombre descriptivo. Por ejemplo: Firefox Auth Testing.
    • Seleccione el botón Aceptar.
    • Para evitar tener que seleccionar el perfil de explorador para cada iteración de pruebas con una aplicación, establezca el perfil como predeterminado con el botón Establecer como predeterminado.
    • Asegúrese 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. Borre las memorias caché del paquete NuGet del sistema local ejecutando dotnet nuget locals all --clear desde un shell de comandos.
  2. Elimine las carpetas bin y obj del proyecto.
  3. Restaure el proyecto y vuelva a compilarlo.
  4. Elimine 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, use la galería de NuGet o el explorador de paquetes FuGet.

Ejecución de la aplicación Server

Al realizar pruebas y solucionar problemas de una solución Blazor hospedada, asegúrese ejecutarla desde el proyecto Server . Por ejemplo, en Visual Studio, confirme que el proyecto Server está resaltado en el Explorador de soluciones antes de iniciar la aplicación con cualquiera de los métodos siguientes:

  • Haga clic en el botón Ejecutar.
  • En el menú, seleccione Depurar > Iniciar depuración.
  • Presione F5.

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

Para descodificar un JSON Web Token (JWT), use 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/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

Recursos adicionales

En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa Azure Active Directory (AAD) para la autenticación.

Registro de aplicaciones en AAD y creación de una solución

Creación de un inquilino

Siga las instrucciones que encontrará en Inicio rápido: Configuración de un inquilino para crear un inquilino en AAD.

Registro de una aplicación de API de servidor

Registre una aplicación de AAD para la aplicación de API de servidor:

  1. Vaya a Azure Active Directory 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 Server AAD).
  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 redirección en este escenario, así que deje la lista desplegable establecida en Web y no especifique ningún URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre la siguiente información:

  • Identificador de aplicación (cliente) de la aplicación de API de servidor; por ejemplo, 41451fa7-82d9-4673-8fa5-69eff5a761fd.
  • Identificador de directorio (inquilino); por ejemplo, e86c78e2-8bb4-4c41-aefd-918e0565a45e.
  • Dominio de AAD Principal/Publicador/Inquilino (por ejemplo, contoso.onmicrosoft.com): El dominio está disponible como Dominio del publicador en la hoja Personalización de marca de Azure Portal de la aplicación registrada.

En Permisos de API, quite el permiso Microsoft Graph > User.Read, ya que la aplicación no necesita el inicio de sesión ni el acceso de perfil de usuario.

En Exponer una API:

  1. Seleccione Agregar un ámbito.
  2. Seleccione Guardar y continuar.
  3. Indique un Nombre de ámbito (por ejemplo, API.Access).
  4. Indique un Nombre para mostrar del consentimiento del administrador (por ejemplo, Access API).
  5. Proporcione una Descripción del consentimiento del administrador (por ejemplo, Allows the app to access server app API endpoints.).
  6. Confirme que Estado está establecido en Habilitado.
  7. Seleccione la opción Agregar un ámbito.

Registre la siguiente información:

  • URI del identificador de aplicación (por ejemplo, api://41451fa7-82d9-4673-8fa5-69eff5a761fd, https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd o el valor personalizado que haya proporcionado)
  • Nombre del ámbito (por ejemplo, API.Access)

Registrar una aplicación cliente

Registre una aplicación de AAD para la aplicación cliente:

  1. Vaya a Azure Active Directory 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 AAD).
  3. Elija un tipo de cuenta compatible. En esta experiencia puede seleccionar Solo cuentas de este directorio organizativo (inquilino único).
  4. Deje la lista desplegable URI de redirección establecida en Web y proporcione el siguiente URI de redirección: https://localhost:{PORT}/authentication/login-callback. El puerto predeterminado de una aplicación que se ejecuta en Kestrel es 5001. Si la aplicación se ejecuta en otro puerto de Kestrel, use el puerto de la aplicación. En el caso de IIS Express, el puerto generado aleatoriamente para la aplicación se encuentra en las propiedades de la aplicación Server , en el panel Depurar. Dado que la aplicación no existe en este momento y no conocemos el puerto de IIS Express, vuelva a este paso después de crear la aplicación y actualice el URI de redirección. En la sección Creación de la aplicación aparece un comentario para recordar a los usuarios de IIS Express que actualicen el URI de redirección.
  5. Si usa un dominio del publicador no comprobado, desactive la casilla Permisos > Conceda consentimiento del administrador a los permisos openid y offline_access. Si el dominio del publicador está comprobado, esta casilla no se muestra.
  6. Seleccione Registrar.

Registre el identificador de la aplicación Client (cliente); por ejemplo, 4369008b-21fa-427c-abaa-9b53bf58e538.

En Autenticación > Configuraciones de plataforma > Web:

  1. Confirme que el URI de redirección de https://localhost:{PORT}/authentication/login-callback está presente.
  2. En Concesión implícita, seleccione las casillas Tokens de acceso y Tokens de id.
  3. Los valores predeterminados restantes de la aplicación son aceptables en esta experiencia.
  4. Seleccione el botón Guardar.

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 AAD).
  4. Abra la lista API.
  5. Habilite el acceso a la API (por ejemplo, API.Access).
  6. Seleccione Agregar permisos.
  7. Seleccione el botón Conceder consentimiento de administrador para {NOMBRE DE INQUILINO} . Seleccione para confirmar la acción.

Creación de la aplicación

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}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} --tenant-id "{TENANT ID}"

Advertencia

Evite usar guiones (-) en el nombre de la aplicación {APP 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, consulte 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
{APP NAME} BlazorSample
{CLIENT APP CLIENT ID} Identificador de aplicación (cliente) para la aplicación Client 4369008b-21fa-427c-abaa-9b53bf58e538
{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 41451fa7-82d9-4673-8fa5-69eff5a761fd
{SERVER API APP ID URI} URI de Id. de aplicación† 41451fa7-82d9-4673-8fa5-69eff5a761fd
{TENANT DOMAIN} Dominio Principal/Publicador/Inquilino contoso.onmicrosoft.com
{TENANT ID} Id. de directorio (inquilino) e86c78e2-8bb4-4c41-aefd-918e0565a45e

†La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al proporcionar el URI de identificador de aplicación para el marcador de posición {SERVER API APP ID URI} y si el esquema es api://, quite el esquema (api://) del argumento, como se muestra en el valor de ejemplo de la tabla anterior. Si el URI de identificador de aplicación es un valor personalizado o tiene algún otro esquema (por ejemplo, https:// para un dominio de publicador no comprobado similar a https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd), debe actualizar manualmente el URI del ámbito predeterminado y quitar el esquema api:// después de que la plantilla cree la aplicación Client . Para obtener más información, consulte la nota de la sección Ámbitos de token de acceso. La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

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 de la aplicación. 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).

Nota

Es posible que se requiera un cambio de configuración al usar un inquilino de Azure con un dominio de publicador no comprobado, lo cual se describe en la sección Ámbitos de token de acceso.

Nota

En Azure Portal, el valor de configuración de plataforma de la aplicación Client URI de redirección de la aplicación se establece en el puerto 5001 en el caso de las aplicaciones que se ejecutan en el servidor Kestrel con la configuración predeterminada.

Si la aplicación Client se ejecuta en un puerto de IIS Express aleatorio, el puerto de la aplicación se encuentra en las propiedades de la aplicación de API de servidor, en el panel Depurar.

Si el puerto no se configuró anteriormente con el puerto conocido de la aplicación Client , vuelva al registro de la aplicación Client en Azure Portal y actualice el URI de redirección con el puerto correcto.

Configuración de la aplicación Server

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

Paquete de autenticación

La compatibilidad con la autenticación y autorización de llamadas realizadas a API web de ASP.NET Core se proporciona a través del paquete Microsoft.AspNetCore.Authentication.AzureAD.UI:

<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" 
  Version="{VERSION}" />

En el caso del marcador de posición {VERSION}, la versión estable más reciente del paquete que coincide con la versión del marco compartida de la aplicación se puede encontrar en el historial de versiones del paquete en NuGet.org.

Compatibilidad con el servicio de autenticació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 método AddAzureADBearer configura los parámetros específicos del controlador de portador JWT necesarios para validar los tokens emitidos por la instancia de Azure Active Directory:

services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
    .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

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();

User.Identity.Name

De manera predeterminada, 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, 2d64b3da-d9d5-42c6-9352-53d8df33d770@contoso.onmicrosoft.com).

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

Configuración de la aplicación

El archivo appsettings.json contiene las opciones para configurar el controlador de portador JWT que se usa para validar los tokens de acceso:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "{DOMAIN}",
    "TenantId": "{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
  }
}

Ejemplo:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "contoso.onmicrosoft.com",
    "TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
  }
}

Controlador WeatherForecast

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]")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

Configuración de la aplicación Client

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

Paquete de autenticació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 agrega autenticación a una aplicación, agregue el paquete manualmente al archivo de proyecto de la aplicación:

<PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" 
  Version="{VERSION}" />

En el caso del marcador de posición {VERSION}, la versión estable más reciente del paquete que coincide con la versión del marco compartida de la aplicación se puede encontrar en el historial de versiones 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

Se ha agregado compatibilidad con instancias de HttpClient que incluye tokens de acceso al realizar solicitudes al proyecto de servidor.

Program.cs:

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

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

El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).

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.

Program.cs:

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 AAD de Azure Portal al registrar la aplicació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": "4369008b-21fa-427c-abaa-9b53bf58e538",
    "ValidateAuthority": true
  }
}

Ámbitos de token de acceso

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

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

Todos los ámbitos deben pertenecer a la misma aplicación según las reglas de Azure Active Directory. En caso necesario, se pueden agregar más ámbitos para otras aplicaciones de API adicionales:

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

Nota

La plantilla Blazor WebAssembly agrega automáticamente un esquema api:// al argumento de URI del identificador de aplicación que se pasa en el comando dotnet new. Al generar una aplicación a partir de la plantilla de proyecto Blazor, confirme que el valor del ámbito de token de acceso predeterminado usa el valor de URI de identificador de aplicación personalizado correcto que proporcionó en Azure Portal o un valor con uno de los siguientes formatos:

  • Cuando el dominio del publicador del directorio es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "api://41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor de un esquema doble (api://api://...). Si hay un esquema doble, quite el primer esquema api:// del valor.

  • Cuando el dominio del publicador del directorio no es de confianza, el ámbito del token de acceso predeterminado suele ser un valor similar al del ejemplo siguiente, donde API.Access es el nombre del ámbito predeterminado:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");
    

    Inspeccione el valor para ver si hay un esquema api:// adicional (api://https://contoso.onmicrosoft.com/...). Si hay un esquema api:// adicional, quite el esquema api:// del valor.

La plantilla Blazor WebAssembly se puede cambiar en una versión futura de ASP.NET Core para abordar estos escenarios. Para obtener más información, consulte Esquema doble para el URI de identificador de aplicación con la plantilla WASM Blazor (hospedada, una sola organización) (dotnet/aspnetcore #27417).

Especifique ámbitos adicionales con AdditionalScopesToConsent:

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

Cuando se trabaja con una API de servidor registrada en AAD y el registro de AAD de la aplicación se encuentra en un inquilino que se basa en un dominio de publicador no comprobado, el URI del identificador de la aplicación de la API del servidor no es api://{SERVER API APP CLIENT ID OR CUSTOM VALUE} sino que, en su lugar, tiene el formato https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}. Si ese es el caso, el ámbito del token de acceso predeterminado en Program.cs de la aplicación Client es similar al siguiente:

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

Para configurar la aplicación de API de servidor para una audiencia coincidente, establezca el valor Audience en el archivo de configuración de la aplicación de API Server (appsettings.json) para que coincida con la audiencia de la aplicación proporcionada por Azure Portal:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "ValidateAuthority": true,
    "Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
  }
}

En la configuración anterior, el final del valor Audience no incluye el ámbito predeterminado /{DEFAULT SCOPE}.

Ejemplo:

En Program.cs de la aplicación Client :

options.ProviderOptions.DefaultAccessTokenScopes
    .Add("https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd/API.Access");

Configure el archivo de configuración de la aplicación de API Server (appsettings.json) con una audiencia correspondiente (Audience):

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
    "ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
    "ValidateAuthority": true,
    "Audience": "https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd"
  }
}

En el ejemplo anterior, el final del valor Audience no incluye el ámbito predeterminado /API.Access.

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

Archivo Imports

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}.Client
@using {APPLICATION ASSEMBLY}.Client.Shared

Página de índice

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

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 al resto 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, use cualquiera de los enfoques siguientes:

  • Cree 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. Inspeccione el componente App (App.razor) en la aplicación generada.

  • Inspeccione el componente App (App.razor) en el origen de referencia.

    Nota

    Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.

Componente RedirectToLogin

El componente RedirectToLogin (Shared/RedirectToLogin.razor):

  • Administra el redireccionamiento de usuarios no autorizados a la página de inicio de sesión.
  • Conserva la dirección URL actual a la que el usuario intenta tener acceso para que pueda volver a esa página si la autenticación se realiza correctamente.
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo(
            $"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

Componente LoginDisplay

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

  • En el caso de los usuarios autenticados:
    • Muestra el nombre de usuario actual.
    • Proporciona un botón para cerrar la sesión de la aplicación.
  • En el caso de los usuarios anónimos, ofrece la posibilidad de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="BeginLogout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <a href="authentication/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

@code {
    private async Task BeginLogout(MouseEventArgs args)
    {
        await SignOutManager.SetSignOutState();
        Navigation.NavigateTo("authentication/logout");
    }
}

Componente Authentication

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; }
}

Componente FetchData

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 se produjo un error en la solicitud porque no se pudo aprovisionar el token sin la interacción del usuario, el resultado del token contiene una dirección 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();
        }
    }
}

Ejecutar la aplicación

Ejecute la aplicación desde el proyecto de servidor. Al usar Visual Studio, puede hacer lo siguiente:

  • Establezca la lista desplegable Proyectos de inicio de la barra de herramientas en la aplicación de API de servidor y seleccione el botón Ejecutar.
  • Seleccione el proyecto de servidor en el Explorador de soluciones y seleccione el botón Ejecutar de la barra de herramientas, o bien inicie la aplicación desde el menú Depurar.

Solución de problemas

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.
    • Un ámbito de token de acceso incorrecto impide 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 otro puerto que no sea el configurado en el URI de redireccionamiento del registro de la aplicación del proveedor de Identity.

    En las secciones de configuración de la guía de este artículo se muestran ejemplos de la configuración correcta. Compruebe 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:

    • Analice los registros de la aplicación.

    • Examine 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á instrucciones sobre las herramientas de desarrollo:

    • Descodifique el contenido de un JSON Web Token (JWT) usado para autenticar un cliente o acceder a una API web del servidor, según dónde esté 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 (abra 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:

    Respecto a los informes de errores del marco que no son de seguridad ni confidenciales, o que no se pueden reproducir, abra una incidencia con la unidad de producto ASP.NET Core. No abra una incidencia con la unidad de producto hasta que haya investigado exhaustivamente su causa y no pueda resolverlo por su 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 por naturaleza o describe un posible error de seguridad en el producto que los atacantes pueden aprovechar, vea Informes de problemas de seguridad y errores (repositorio de GitHub dotnet/aspnetcore).

  • Cliente no autorizado para AAD

    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 AAD:

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

    Para resolver el error:

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

Cookies y datos del sitio

Las Cookies y los datos del sitio pueden persistir entre las actualizaciones de la aplicación e interferir con las pruebas y la solución de problemas. Borre 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 del usuario
  • cookies de aplicaciones
  • Datos de sitios almacenados y en caché

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

  • Configuración de un explorador
    • Use un explorador para las pruebas, y configúrelo para que elimine todas las cookies y los datos del sitio cada vez que se cierre.
    • Asegúrese 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.
  • Use un comando personalizado para abrir un explorador en el modo incógnito o privado en Visual Studio:
    • Abra el cuadro de diálogo Examinar con mediante el botón Ejecutar de Visual Studio.
    • Seleccione el botón Agregar.
    • Proporcione 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, proporcione 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, proporcione 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: Use -inprivate.
      • Google Chrome: Use --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: Use -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).
    • Proporcione un nombre en el campo Nombre descriptivo. Por ejemplo: Firefox Auth Testing.
    • Seleccione el botón Aceptar.
    • Para evitar tener que seleccionar el perfil de explorador para cada iteración de pruebas con una aplicación, establezca el perfil como predeterminado con el botón Establecer como predeterminado.
    • Asegúrese 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. Borre las memorias caché del paquete NuGet del sistema local ejecutando dotnet nuget locals all --clear desde un shell de comandos.
  2. Elimine las carpetas bin y obj del proyecto.
  3. Restaure el proyecto y vuelva a compilarlo.
  4. Elimine 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, use la galería de NuGet o el explorador de paquetes FuGet.

Ejecución de la aplicación Server

Al realizar pruebas y solucionar problemas de una solución Blazor hospedada, asegúrese ejecutarla desde el proyecto Server . Por ejemplo, en Visual Studio, confirme que el proyecto Server está resaltado en el Explorador de soluciones antes de iniciar la aplicación con cualquiera de los métodos siguientes:

  • Haga clic en el botón Ejecutar.
  • En el menú, seleccione Depurar > Iniciar depuración.
  • Presione F5.

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

Para descodificar un JSON Web Token (JWT), use 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/5cc15ea8-a296-4aa3-97e4-226dcc9ad298/v2.0/",
  "sub": "5ee963fb-24d6-4d72-a1b6-889c6e2c7438",
  "aud": "70bde375-fce3-4b82-984a-b247d823a03f",
  "nonce": "b2641f54-8dc4-42ca-97ea-7f12ff4af871",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

Recursos adicionales