Protección de una Blazor Web App de ASP.NET Core con OpenID Connect (OIDC)
En este artículo se describe cómo proteger un objeto Blazor Web App con OpenID Connect (OIDC) mediante una aplicación de ejemplo en el repositorio de GitHub dotnet/blazor-samples
(.NET 8 o posterior) (cómo descargar).
En esta versión del artículo se describe la implementación de OIDC sin adoptar el patrón BFF (Backend for Frontend). El patrón BFF es útil para realizar solicitudes autenticadas a servicios externos. Cambia el selector de versión del artículo a OIDC con el patrón BFF si la especificación de la aplicación llama a adoptar el patrón BFF.
Se trata la especificación siguiente:
- La Blazor Web App usa el modo de representación automática con interactividad global.
- Las aplicaciones cliente y el servidor usan los servicios de proveedor de estado de autenticación personalizados para capturar el estado de autenticación del usuario y hacer que fluya entre el servidor y el cliente.
- Esta aplicación es un punto de partida para cualquier flujo de autenticación de OIDC. OIDC se configura manualmente en la aplicación y no se basa en los paquetes Microsoft Entra ID ni Microsoft Identity Web, y la aplicación de ejemplo tampoco requiere el hospedaje de Microsoft Azure. Sin embargo, la aplicación de ejemplo puede usarse con Entra y Microsoft Identity Web, y hospedarse en Azure.
- Actualización automática de token no interactivo.
- Llama de forma segura a una API (web) en el proyecto de servidor para obtener datos.
Aplicación de ejemplo
El ejemplo consta de dos proyectos:
BlazorWebAppOidc
: proyecto del lado servidor de la Blazor Web App, que contiene un punto de conexión de API mínima de ejemplo para datos meteorológicos.BlazorWebAppOidc.Client
: proyecto del lado cliente de la Blazor Web App.
Accede a las aplicaciones de ejemplo a través de la carpeta de versión más reciente desde la raíz del repositorio con el vínculo siguiente. Los proyectos se encuentran en la carpeta BlazorWebAppOidc
de .NET 8 o posterior.
Vea o descargue el código de ejemplo (cómo descargarlo)
Proyecto de Blazor Web App del lado servidor (BlazorWebAppOidc
)
El proyecto BlazorWebAppOidc
es el proyecto del lado servidor de la Blazor Web App.
El archivo BlazorWebAppOidc.http
se puede usar para probar la solicitud de datos meteorológicos. Ten en cuenta que el proyecto BlazorWebAppOidc
debe ejecutarse para probar el punto de conexión y el punto de conexión está codificado de forma dura en el archivo. Para obtener más información, consulta Usar archivos .http en Visual Studio 2022.
Nota:
El proyecto de servidor usa IHttpContextAccessor/HttpContext, pero nunca para componentes representados de forma interactiva. Para obtener más información, consulta Guía de mitigación de amenazas para Blazor la representación interactiva en el lado del servidor de ASP.NET Core.
Configuración
En esta sección se explica cómo configurar la aplicación de ejemplo.
Nota:
En el caso de Microsoft Entra ID o Azure AD B2C, puede usar AddMicrosoftIdentityWebApp desde Microsoft Identity Web (Microsoft.Identity.Web
paquete NuGet, documentación de API), que agrega los controladores de autenticación y Cookie OIDC con los valores predeterminados adecuados. La aplicación de ejemplo y las instrucciones de esta sección no usan Microsoft Identity Web. En la guía se muestra cómo configurar el controlador OIDC manualmente para cualquier proveedor de OIDC. Para obtener más información sobre la implementación de Microsoft Identity Web, consulta los recursos vinculados.
Establecimiento del secreto de cliente
Advertencia
No almacene secretos de aplicación, cadena de conexión s, credenciales, contraseñas, números de identificación personal (PIN), código C#/.NET privado o claves o tokens privados en el código del lado cliente, lo que siempre es inseguro. En entornos de prueba/ensayo y producción, el código del lado Blazor servidor y las API web deben usar flujos de autenticación seguros que eviten mantener las credenciales dentro del código del proyecto o los archivos de configuración. Fuera de las pruebas de desarrollo local, se recomienda evitar el uso de variables de entorno para almacenar datos confidenciales, ya que las variables de entorno no son el enfoque más seguro. Para las pruebas de desarrollo local, se recomienda la herramienta Secret Manager para proteger los datos confidenciales. Para obtener más información, consulte Mantener de forma segura los datos confidenciales y las credenciales.
Para las pruebas de desarrollo local, use la herramienta Administrador de secretos para almacenar el secreto de cliente de la aplicación de servidor en la clave Authentication:Schemes:MicrosoftOidc:ClientSecret
de configuración .
Nota:
Si la aplicación usa Microsoft Entra ID o Azure AD B2C, cree un secreto de cliente en el registro de la aplicación en Entra o Azure Portal (Administrar>certificados y secretos>Nuevo secreto de cliente). Use el valor del nuevo secreto en las instrucciones siguientes.
La aplicación de ejemplo no se ha inicializado para la herramienta Administrador de secretos. Use un shell de comandos, como el shell de comandos de PowerShell para desarrolladores en Visual Studio, para ejecutar el comando siguiente. Antes de ejecutar el comando, cambie el directorio con el cd
comando al directorio del proyecto de servidor. El comando establece un identificador de secretos de usuario (<UserSecretsId>
en el archivo de proyecto de la aplicación de servidor):
dotnet user-secrets init
Ejecute el siguiente comando para establecer el secreto de cliente. El {SECRET}
marcador de posición es el secreto de cliente obtenido del registro de la aplicación:
dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"
Si usa Visual Studio, puede confirmar que el secreto está establecido haciendo clic con el botón derecho en el proyecto de servidor en Explorador de soluciones y seleccionando Administrar secretos de usuario.
Configuración de la aplicación
La siguiente configuración OpenIdConnectOptions se encuentra en el archivo del proyecto Program
en la llamada a AddOpenIdConnect:
SignInScheme: establece el esquema de autenticación correspondiente al middleware responsable de conservar identity del usuario después de una autenticación correcta. El controlador OIDC debe usar un esquema de inicio de sesión que sea capaz de conservar las credenciales de usuario entre las solicitudes. La siguiente línea se presenta simplemente con fines de demostración. Si se omite, DefaultSignInScheme se usa como valor de reserva.
oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
Ámbitos para
openid
yprofile
(Scope) (opcional): los ámbitosopenid
yprofile
también se configuran de forma predeterminada porque son necesarios para que el controlador OIDC funcione, pero es posible que deban volver a agregarse si los ámbitos se incluyen en la configuración deAuthentication:Schemes:MicrosoftOidc:Scope
. Para obtener instrucciones generales de configuración, consulta Configuración en ASP.NET Core y Configuración de Blazor de ASP.NET Core.oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
SaveTokens: define si los tokens de acceso y actualización deben almacenarse en AuthenticationProperties después de una autorización correcta. Esta propiedad se establece en
false
para reducir el tamaño de cookie de autenticación final.oidcOptions.SaveTokens = false;
Ámbito para el acceso sin conexión (Scope): el ámbito
offline_access
es necesario para el token de actualización.oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
Authority y ClientId: establece la autoridad y el id. de cliente para las llamadas de OIDC.
oidcOptions.Authority = "{AUTHORITY}"; oidcOptions.ClientId = "{CLIENT ID}";
Ejemplo:
- Autoridad (
{AUTHORITY}
):https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/
(usa el id. de inquilinoaaaabbbb-0000-cccc-1111-dddd2222eeee
) - Id. de cliente (
{CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
Ejemplo de autoridad "común" de Microsoft Azure:
La entidad "común" debe usarse para aplicaciones multiinquilino. También puedes usar la entidad "común" para las aplicaciones de un solo inquilino, pero se requiere un IssuerValidator personalizado, como se muestra más adelante en esta sección.
oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
- Autoridad (
ResponseType: configura el controlador OIDC para que solo realice el flujo de código de autorización. Las concesiones implícitas y los flujos híbridos no son necesarios en este modo.
En la configuración de registro de aplicaciones de flujos híbridos y concesión implícita de Entra o Azure Portal, no actives ninguna casilla de selección para que el punto de conexión de autorización devuelva Tokens de acceso o Tokens de id.. El controlador OIDC solicita automáticamente los tokens adecuados mediante el código que devuelve el punto de conexión de autorización.
oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
MapInboundClaims y configuración de NameClaimType y RoleClaimType: muchos servidores OIDC usan "
name
" y "role
" en lugar de los valores predeterminados de SOAP/WS-Fed en ClaimTypes. Cuando MapInboundClaims se establece enfalse
, el controlador no realiza asignaciones de notificaciones y la aplicación usa directamente los nombres de notificación del JWT. En el ejemplo siguiente, se establece el tipo de notificación de rol en "roles
", que es adecuado para Microsoft Entra ID (ME-ID). Para más información, consulta la documentación de tu proveedor de identity.Nota:
MapInboundClaims debe establecerse en
false
para la mayoría de los proveedores de OIDC, lo que impide cambiar el nombre de las notificaciones.oidcOptions.MapInboundClaims = false; oidcOptions.TokenValidationParameters.NameClaimType = "name"; oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
Configuración de rutas: las rutas deben coincidir con las rutas del URI de redirección (ruta de devolución de llamada de inicio de sesión) y la redirección posterior al cierre de sesión (ruta de devolución de llamada de cierre de sesión) configuradas al registrar la aplicación con el proveedor OIDC. En Azure Portal, las rutas se configuran en la hoja Autenticación del registro de la aplicación. Las rutas de inicio de sesión y cierre de sesión deben registrarse como URI de redirección. Los valores predeterminados son
/signin-oidc
y/signout-callback-oidc
.CallbackPath: ruta de solicitud en la ruta base de la aplicación en la que se devolverá el agente de usuario.
En Entra o Azure Portal, establece la ruta en el URI de redirección de la configuración de la plataforma web:
https://localhost/signin-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
cuando se usa Microsoft Entra ID. La mayoría de los otros proveedores de OIDC requieren un puerto correcto.SignedOutCallbackPath: ruta de solicitud en la ruta base de la aplicación en la que se devolverá el agente de usuario después de cerrar la sesión del proveedor de identity.
En Entra o Azure Portal, establece la ruta en el URI de redirección de la configuración de la plataforma web:
https://localhost/signout-callback-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
cuando se usa Microsoft Entra ID. La mayoría de los otros proveedores de OIDC requieren un puerto correcto.Nota:
Si usas Microsoft Identity Web, actualmente el proveedor solo redirige de nuevo a SignedOutCallbackPath si se usa la autoridad de
microsoftonline.com
(https://login.microsoftonline.com/{TENANT ID}/v2.0/
). Esta limitación no existe si puedes usar la autoridad "común" con Microsoft Identity Web. Para obtener más información, consulta postLogoutRedirectUri no funciona cuando la dirección URL de autoridad contiene un id. de inquilino (AzureAD/microsoft-authentication-library-for-js
#5783).RemoteSignOutPath: las solicitudes recibidas en esta ruta hacen que el controlador invoque el cierre de sesión mediante el esquema de cierre de sesión.
En Entra o Azure Portal, establece la URL de cierre de sesión de Front-Channel:
https://localhost/signout-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
cuando se usa Microsoft Entra ID. La mayoría de los otros proveedores de OIDC requieren un puerto correcto.oidcOptions.CallbackPath = new PathString("{PATH}"); oidcOptions.SignedOutCallbackPath = new PathString("{PATH}"); oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
Ejemplos (valores predeterminados):
oidcOptions.CallbackPath = new PathString("/signin-oidc"); oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc"); oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
(Microsoft Azure solo con el punto de conexión "común") TokenValidationParameters.IssuerValidator: muchos proveedores de OIDC funcionan con el validador de emisor predeterminado, pero es necesario tener en cuenta el emisor parametrizado con el id. de inquilino (
{TENANT ID}
) devuelto porhttps://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
. Para obtener más información, consulta SecurityTokenInvalidIssuerException con OpenID Connect y el punto de conexión "común" de Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet
#1731).Solo para las aplicaciones que usan Microsoft Entra ID o Azure AD B2C con el punto de conexión "común":
var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority); oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
Código de aplicación de ejemplo
Inspecciona la aplicación de ejemplo para ver las siguientes características:
- Actualización automática de tokens no interactivos con la ayuda de un actualizador personalizado cookie (
CookieOidcRefresher.cs
). - El proyecto de servidor llama
AddAuthenticationStateSerialization
a para agregar un proveedor de estado de autenticación del lado servidor que usa PersistentComponentState para fluir el estado de autenticación al cliente. El cliente llamaAddAuthenticationStateDeserialization
a para deserializar y usar el estado de autenticación pasado por el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly. - Un ejemplo de solicitudes a la Blazor Web App para datos meteorológicos se controla mediante un punto de conexión de API mínima (
/weather-forecast
) en el archivoProgram
(Program.cs
). El punto de conexión requiere autorización llamando a RequireAuthorization. Para los controladores que agregues al proyecto, agrega el atributo[Authorize]
al controlador o la acción. - La aplicación llama de forma segura a una API (web) en el proyecto de servidor para obtener los datos meteorológicos:
- Al representar el componente
Weather
en el servidor, el componente usa elServerWeatherForecaster
en el servidor para obtener los datos meteorológicos directamente (no a través de una llamada API web). - Cuando el componente se representa en el cliente, usa la implementación del servicio
ClientWeatherForecaster
, que usa un HttpClient preconfigurado (en el archivoProgram
del proyecto de cliente) para realizar una llamada API web al proyecto de servidor. Un punto de conexión de API mínimo (/weather-forecast
) definido en el archivoProgram
del proyecto de servidor obtiene los datos meteorológicos de laServerWeatherForecaster
y devuelve los datos al cliente.
- Al representar el componente
- Actualización automática de tokens no interactivos con la ayuda de un actualizador personalizado cookie (
CookieOidcRefresher.cs
). - La clase
PersistingAuthenticationStateProvider
(PersistingAuthenticationStateProvider.cs
) es un AuthenticationStateProvider del lado servidor que usa PersistentComponentState para hacer fluir el estado de autenticación, que posteriormente es fijo durante la vigencia de la aplicación WebAssembly, al cliente. - Un ejemplo de solicitudes a la Blazor Web App para datos meteorológicos se controla mediante un punto de conexión de API mínima (
/weather-forecast
) en el archivoProgram
(Program.cs
). El punto de conexión requiere autorización llamando a RequireAuthorization. Para los controladores que agregues al proyecto, agrega el atributo[Authorize]
al controlador o la acción. - La aplicación llama de forma segura a una API (web) en el proyecto de servidor para obtener los datos meteorológicos:
- Al representar el componente
Weather
en el servidor, el componente usa elServerWeatherForecaster
en el servidor para obtener los datos meteorológicos directamente (no a través de una llamada API web). - Cuando el componente se representa en el cliente, usa la implementación del servicio
ClientWeatherForecaster
, que usa un HttpClient preconfigurado (en el archivoProgram
del proyecto de cliente) para realizar una llamada API web al proyecto de servidor. Un punto de conexión de API mínimo (/weather-forecast
) definido en el archivoProgram
del proyecto de servidor obtiene los datos meteorológicos de laServerWeatherForecaster
y devuelve los datos al cliente.
- Al representar el componente
Para obtener más información sobre las llamadas API (web) mediante abstracciones de servicio en Blazor Web App, consulta Llamada a una API web desde una aplicación Blazor de ASP.NET Core.
Proyecto de Blazor Web App del lado cliente (BlazorWebAppOidc.Client
)
El proyecto BlazorWebAppOidc.Client
es el proyecto del lado cliente de Blazor Web App.
El cliente llama AddAuthenticationStateDeserialization
a para deserializar y usar el estado de autenticación pasado por el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly.
La clase PersistentAuthenticationStateProvider
(PersistentAuthenticationStateProvider.cs
) es un AuthenticationStateProvider del lado cliente que determina el estado de autenticación del usuario buscando datos guardados en la página cuando se representa en el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly.
Si el usuario necesita iniciar sesión o cerrar sesión, se requiere una recarga de página completa.
La aplicación de ejemplo solo proporciona un nombre de usuario y un correo electrónico con fines de demostración. No incluye tokens que se autentican en el servidor al realizar solicitudes posteriores, que funcionan por separado mediante un cookie que se incluye en solicitudes HttpClient al servidor.
En esta versión del artículo se describe la implementación de OIDC con el patrón BFF (Backend for Frontend). Cambia el selector de versión del artículo a OIDC sin el patrón BFF si la especificación de la aplicación no llama a adoptar el patrón BFF.
Se trata la especificación siguiente:
- La Blazor Web App usa el modo de representación automática con interactividad global.
- Las aplicaciones cliente y el servidor usan los servicios de proveedor de estado de autenticación personalizados para capturar el estado de autenticación del usuario y hacer que fluya entre el servidor y el cliente.
- Esta aplicación es un punto de partida para cualquier flujo de autenticación de OIDC. OIDC se configura manualmente en la aplicación y no se basa en los paquetes Microsoft Entra ID ni Microsoft Identity Web, y la aplicación de ejemplo tampoco requiere el hospedaje de Microsoft Azure. Sin embargo, la aplicación de ejemplo puede usarse con Entra y Microsoft Identity Web, y hospedarse en Azure.
- Actualización automática de token no interactivo.
- El patrón Backend for Frontend (BFF) se adopta mediante .NET Aspire para la detección de servicios y YARP para redirigir mediante proxy solicitudes a un punto de conexión de previsión meteorológica en la aplicación back-end.
- Una API web de back-end usa la autenticación de portador JWT para validar los tokens JWT guardados por la Blazor Web App en la cookie de inicio de sesión.
- Aspire mejora la experiencia de creación de aplicaciones nativas de nube .NET. Proporciona un conjunto coherente y fundamentado de herramientas y patrones para compilar y ejecutar aplicaciones distribuidas.
- YARP es una biblioteca que se usa para crear un servidor proxy inverso.
Para obtener más información sobre .NET Aspire, consulta Disponibilidad general de .NET Aspire: simplificación del desarrollo nativo de nube de .NET (mayo de 2024).
Requisito previo
.NET Aspire requiere Visual Studio versión 17.10 o versión posterior.
Aplicación de ejemplo
El ejemplo consta de cinco proyectos:
- .NET Aspire:
Aspire.AppHost
: se usa para administrar los problemas de orquestación de nivel general de la aplicación.Aspire.ServiceDefaults
: contiene configuraciones de aplicaciones .NET Aspire predeterminadas que se pueden ampliar y personalizar según sea necesario.
MinimalApiJwt
: API web de back-end, que contiene un punto de conexión de API mínima de ejemplo para los datos meteorológicos.BlazorWebAppOidc
: proyecto del lado servidor de la Blazor Web App.BlazorWebAppOidc.Client
: proyecto del lado cliente de la Blazor Web App.
Accede a las aplicaciones de ejemplo a través de la carpeta de versión más reciente desde la raíz del repositorio con el vínculo siguiente. Los proyectos se encuentran en la carpeta BlazorWebAppOidcBff
de .NET 8 o posterior.
Consulta o descarga el código de ejemplo (cómo descargarlo)
Proyectos .NET Aspire
Para obtener más información sobre el uso de .NET Aspire y detalles sobre los proyectos .AppHost
y .ServiceDefaults
de la aplicación de ejemplo, consulta la documentación de .NET Aspire.
Confirma que cumples los requisitos previos para .NET Aspire. Para obtener más información, consulta la sección Requisitos previos de Inicio rápido: Compilación de la primera aplicación .NET Aspire.
La aplicación de muestra solo configura un perfil de inicio HTTP no seguro (http
) para usarlo durante las pruebas de desarrollo. Para obtener más información, incluido un ejemplo de perfiles de configuración de inicio seguro y no seguro, consulta Permitir el transporte no seguro en .NET Aspire (documentación de .NET Aspire).
Proyecto de Blazor Web App del lado servidor (BlazorWebAppOidc
)
El proyecto BlazorWebAppOidc
es el proyecto del lado servidor de la Blazor Web App. El proyecto usa YARP para redirigir mediante proxy las solicitudes a un punto de conexión de previsión meteorológica en el proyecto de API web de back-end (MinimalApiJwt
) con access_token
almacenado en la cookie de autenticación.
El archivo BlazorWebAppOidc.http
se puede usar para probar la solicitud de datos meteorológicos. Ten en cuenta que el proyecto BlazorWebAppOidc
debe ejecutarse para probar el punto de conexión y el punto de conexión está codificado de forma dura en el archivo. Para obtener más información, consulta Usar archivos .http en Visual Studio 2022.
Nota:
El proyecto de servidor usa IHttpContextAccessor/HttpContext, pero nunca para componentes representados de forma interactiva. Para obtener más información, consulta Guía de mitigación de amenazas para Blazor la representación interactiva en el lado del servidor de ASP.NET Core.
Configuración
En esta sección se explica cómo configurar la aplicación de ejemplo.
Nota:
En el caso de Microsoft Entra ID o Azure AD B2C, puede usar AddMicrosoftIdentityWebApp desde Microsoft Identity Web (Microsoft.Identity.Web
paquete NuGet, documentación de API), que agrega los controladores de autenticación y Cookie OIDC con los valores predeterminados adecuados. La aplicación de ejemplo y las instrucciones de esta sección no usan Microsoft Identity Web. En la guía se muestra cómo configurar el controlador OIDC manualmente para cualquier proveedor de OIDC. Para obtener más información sobre la implementación de Microsoft Identity Web, consulta los recursos vinculados.
Establecimiento del secreto de cliente
Advertencia
No almacene secretos de aplicación, cadena de conexión s, credenciales, contraseñas, números de identificación personal (PIN), código C#/.NET privado o claves o tokens privados en el código del lado cliente, lo que siempre es inseguro. En entornos de prueba/ensayo y producción, el código del lado Blazor servidor y las API web deben usar flujos de autenticación seguros que eviten mantener las credenciales dentro del código del proyecto o los archivos de configuración. Fuera de las pruebas de desarrollo local, se recomienda evitar el uso de variables de entorno para almacenar datos confidenciales, ya que las variables de entorno no son el enfoque más seguro. Para las pruebas de desarrollo local, se recomienda la herramienta Secret Manager para proteger los datos confidenciales. Para obtener más información, consulte Mantener de forma segura los datos confidenciales y las credenciales.
Para las pruebas de desarrollo local, use la herramienta Administrador de secretos para almacenar el secreto de cliente de la aplicación de servidor en la clave Authentication:Schemes:MicrosoftOidc:ClientSecret
de configuración .
Nota:
Si la aplicación usa Microsoft Entra ID o Azure AD B2C, cree un secreto de cliente en el registro de la aplicación en Entra o Azure Portal (Administrar>certificados y secretos>Nuevo secreto de cliente). Use el valor del nuevo secreto en las instrucciones siguientes.
La aplicación de ejemplo no se ha inicializado para la herramienta Administrador de secretos. Use un shell de comandos, como el shell de comandos de PowerShell para desarrolladores en Visual Studio, para ejecutar el comando siguiente. Antes de ejecutar el comando, cambie el directorio con el cd
comando al directorio del proyecto de servidor. El comando establece un identificador de secretos de usuario (<UserSecretsId>
en el archivo de proyecto de la aplicación de servidor):
dotnet user-secrets init
Ejecute el siguiente comando para establecer el secreto de cliente. El {SECRET}
marcador de posición es el secreto de cliente obtenido del registro de la aplicación:
dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"
Si usa Visual Studio, puede confirmar que el secreto está establecido haciendo clic con el botón derecho en el proyecto de servidor en Explorador de soluciones y seleccionando Administrar secretos de usuario.
Configuración de la aplicación
La siguiente configuración OpenIdConnectOptions se encuentra en el archivo del proyecto Program
en la llamada a AddOpenIdConnect:
SignInScheme: establece el esquema de autenticación correspondiente al middleware responsable de conservar identity del usuario después de una autenticación correcta. El controlador OIDC debe usar un esquema de inicio de sesión que sea capaz de conservar las credenciales de usuario entre las solicitudes. La siguiente línea se presenta simplemente con fines de demostración. Si se omite, DefaultSignInScheme se usa como valor de reserva.
oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
Ámbitos para
openid
yprofile
(Scope) (opcional): los ámbitosopenid
yprofile
también se configuran de forma predeterminada porque son necesarios para que el controlador OIDC funcione, pero es posible que deban volver a agregarse si los ámbitos se incluyen en la configuración deAuthentication:Schemes:MicrosoftOidc:Scope
. Para obtener instrucciones generales de configuración, consulta Configuración en ASP.NET Core y Configuración de Blazor de ASP.NET Core.oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
SaveTokens: define si los tokens de acceso y actualización deben almacenarse en AuthenticationProperties después de una autorización correcta. El valor se establece en
true
para autenticar las solicitudes de datos meteorológicos del proyecto de API web de back-end (MinimalApiJwt
).oidcOptions.SaveTokens = true;
Ámbito para el acceso sin conexión (Scope): el ámbito
offline_access
es necesario para el token de actualización.oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
Ámbitos para obtener datos meteorológicos de la API web (Scope): el ámbito
Weather.Get
se configura en Entra o Azure Portal en Exponer una API. Esto es necesario para el proyecto de API web de back-end (MinimalApiJwt
) de cara a validar el token de acceso con JWT de portador.oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
Ejemplo:
- URI de identificador de aplicación (
{APP ID URI}
):https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
- Nombre del directorio (
{DIRECTORY NAME}
):contoso
- Identificador de aplicación (cliente) (
{CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
- Nombre del directorio (
- Ámbito configurado para los datos meteorológicos de
MinimalApiJwt
({API NAME}
):Weather.Get
oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
El ejemplo anterior pertenece a una aplicación registrada en un inquilino con un tipo de inquilino de AAD B2C. Si la aplicación está registrada en un inquilino ME-ID, el URI de identificador de aplicación es diferente, por lo que el ámbito es diferente.
Ejemplo:
- URI de identificador de aplicación (
{APP ID URI}
):api://{CLIENT ID}
con identificador de aplicación (cliente) ({CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
- Ámbito configurado para los datos meteorológicos de
MinimalApiJwt
({API NAME}
):Weather.Get
oidcOptions.Scope.Add("api://00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
- URI de identificador de aplicación (
Authority y ClientId: establece la autoridad y el id. de cliente para las llamadas de OIDC.
oidcOptions.Authority = "{AUTHORITY}"; oidcOptions.ClientId = "{CLIENT ID}";
Ejemplo:
- Autoridad (
{AUTHORITY}
):https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/
(usa el id. de inquilinoaaaabbbb-0000-cccc-1111-dddd2222eeee
) - Id. de cliente (
{CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
Ejemplo de autoridad "común" de Microsoft Azure:
La entidad "común" debe usarse para aplicaciones multiinquilino. También puedes usar la entidad "común" para las aplicaciones de un solo inquilino, pero se requiere un IssuerValidator personalizado, como se muestra más adelante en esta sección.
oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
- Autoridad (
ResponseType: configura el controlador OIDC para que solo realice el flujo de código de autorización. Las concesiones implícitas y los flujos híbridos no son necesarios en este modo.
En la configuración de registro de aplicaciones de flujos híbridos y concesión implícita de Entra o Azure Portal, no actives ninguna casilla de selección para que el punto de conexión de autorización devuelva Tokens de acceso o Tokens de id.. El controlador OIDC solicita automáticamente los tokens adecuados mediante el código que devuelve el punto de conexión de autorización.
oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
MapInboundClaims y configuración de NameClaimType y RoleClaimType: muchos servidores OIDC usan "
name
" y "role
" en lugar de los valores predeterminados de SOAP/WS-Fed en ClaimTypes. Cuando MapInboundClaims se establece enfalse
, el controlador no realiza asignaciones de notificaciones y la aplicación usa directamente los nombres de notificación del JWT. En el ejemplo siguiente, se establece el tipo de notificación de rol en "roles
", que es adecuado para Microsoft Entra ID (ME-ID). Para más información, consulta la documentación de tu proveedor de identity.Nota:
MapInboundClaims debe establecerse en
false
para la mayoría de los proveedores de OIDC, lo que impide cambiar el nombre de las notificaciones.oidcOptions.MapInboundClaims = false; oidcOptions.TokenValidationParameters.NameClaimType = "name"; oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
Configuración de rutas: las rutas deben coincidir con las rutas del URI de redirección (ruta de devolución de llamada de inicio de sesión) y la redirección posterior al cierre de sesión (ruta de devolución de llamada de cierre de sesión) configuradas al registrar la aplicación con el proveedor OIDC. En Azure Portal, las rutas se configuran en la hoja Autenticación del registro de la aplicación. Las rutas de inicio de sesión y cierre de sesión deben registrarse como URI de redirección. Los valores predeterminados son
/signin-oidc
y/signout-callback-oidc
.CallbackPath: ruta de solicitud en la ruta base de la aplicación en la que se devolverá el agente de usuario.
En Entra o Azure Portal, establece la ruta en el URI de redirección de la configuración de la plataforma web:
https://localhost/signin-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
.SignedOutCallbackPath: ruta de solicitud en la ruta base de la aplicación en la que se devolverá el agente de usuario después de cerrar la sesión del proveedor de identity.
En Entra o Azure Portal, establece la ruta en el URI de redirección de la configuración de la plataforma web:
https://localhost/signout-callback-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
.Nota:
Si usas Microsoft Identity Web, actualmente el proveedor solo redirige de nuevo a SignedOutCallbackPath si se usa la autoridad de
microsoftonline.com
(https://login.microsoftonline.com/{TENANT ID}/v2.0/
). Esta limitación no existe si puedes usar la autoridad "común" con Microsoft Identity Web. Para obtener más información, consulta postLogoutRedirectUri no funciona cuando la dirección URL de autoridad contiene un id. de inquilino (AzureAD/microsoft-authentication-library-for-js
#5783).RemoteSignOutPath: las solicitudes recibidas en esta ruta hacen que el controlador invoque el cierre de sesión mediante el esquema de cierre de sesión.
En Entra o Azure Portal, establece la URL de cierre de sesión de Front-Channel:
https://localhost/signout-oidc
Nota:
No se requiere un puerto para las direcciones
localhost
.oidcOptions.CallbackPath = new PathString("{PATH}"); oidcOptions.SignedOutCallbackPath = new PathString("{PATH}"); oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
Ejemplos (valores predeterminados):
oidcOptions.CallbackPath = new PathString("/signin-oidc"); oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc"); oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
(Microsoft Azure solo con el punto de conexión "común") TokenValidationParameters.IssuerValidator: muchos proveedores de OIDC funcionan con el validador de emisor predeterminado, pero es necesario tener en cuenta el emisor parametrizado con el id. de inquilino (
{TENANT ID}
) devuelto porhttps://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
. Para obtener más información, consulta SecurityTokenInvalidIssuerException con OpenID Connect y el punto de conexión "común" de Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet
#1731).Solo para las aplicaciones que usan Microsoft Entra ID o Azure AD B2C con el punto de conexión "común":
var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority); oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
Código de aplicación de ejemplo
Inspecciona la aplicación de ejemplo para ver las siguientes características:
- Actualización automática de tokens no interactivos con la ayuda de un actualizador personalizado cookie (
CookieOidcRefresher.cs
). - El proyecto de servidor llama
AddAuthenticationStateSerialization
a para agregar un proveedor de estado de autenticación del lado servidor que usa PersistentComponentState para fluir el estado de autenticación al cliente. El cliente llamaAddAuthenticationStateDeserialization
a para deserializar y usar el estado de autenticación pasado por el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly. - Las solicitudes a la Blazor Web App se redirigen mediante proxy al proyecto de API web de back-end (
MinimalApiJwt
). ElMapForwarder
en el archivoProgram
agrega reenvío directo de solicitudes HTTP que coinciden con el patrón especificado a un destino específico mediante la configuración predeterminada para la solicitud saliente, las transformaciones personalizadas y el cliente HTTP predeterminado:- Al representar el componente
Weather
en el servidor, el componente usa elServerWeatherForecaster
para redirigir mediante proxy la solicitud de datos meteorológicos con el token de acceso del usuario. - Cuando el componente se representa en el cliente, usa la implementación del servicio
ClientWeatherForecaster
, que usa un HttpClient preconfigurado (en el archivoProgram
del proyecto de cliente) para realizar una llamada API web al proyecto de servidor. Un punto de conexión de API mínimo (/weather-forecast
) definido en el archivoProgram
del proyecto de servidor transforma la solicitud con el token de acceso del usuario para obtener los datos meteorológicos.
- Al representar el componente
- Actualización automática de tokens no interactivos con la ayuda de un actualizador personalizado cookie (
CookieOidcRefresher.cs
). - La clase
PersistingAuthenticationStateProvider
(PersistingAuthenticationStateProvider.cs
) es un AuthenticationStateProvider del lado servidor que usa PersistentComponentState para hacer fluir el estado de autenticación, que posteriormente es fijo durante la vigencia de la aplicación WebAssembly, al cliente. - Las solicitudes a la Blazor Web App se redirigen mediante proxy al proyecto de API web de back-end (
MinimalApiJwt
). ElMapForwarder
en el archivoProgram
agrega reenvío directo de solicitudes HTTP que coinciden con el patrón especificado a un destino específico mediante la configuración predeterminada para la solicitud saliente, las transformaciones personalizadas y el cliente HTTP predeterminado:- Al representar el componente
Weather
en el servidor, el componente usa elServerWeatherForecaster
para redirigir mediante proxy la solicitud de datos meteorológicos con el token de acceso del usuario. - Cuando el componente se representa en el cliente, usa la implementación del servicio
ClientWeatherForecaster
, que usa un HttpClient preconfigurado (en el archivoProgram
del proyecto de cliente) para realizar una llamada API web al proyecto de servidor. Un punto de conexión de API mínimo (/weather-forecast
) definido en el archivoProgram
del proyecto de servidor transforma la solicitud con el token de acceso del usuario para obtener los datos meteorológicos.
- Al representar el componente
Para obtener más información sobre las llamadas API (web) mediante abstracciones de servicio en Blazor Web App, consulta Llamada a una API web desde una aplicación Blazor de ASP.NET Core.
Proyecto de Blazor Web App del lado cliente (BlazorWebAppOidc.Client
)
El proyecto BlazorWebAppOidc.Client
es el proyecto del lado cliente de Blazor Web App.
El cliente llama AddAuthenticationStateDeserialization
a para deserializar y usar el estado de autenticación pasado por el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly.
La clase PersistentAuthenticationStateProvider
(PersistentAuthenticationStateProvider.cs
) es un AuthenticationStateProvider del lado cliente que determina el estado de autenticación del usuario buscando datos guardados en la página cuando se representa en el servidor. El estado de autenticación es fijo durante la vigencia de la aplicación WebAssembly.
Si el usuario necesita iniciar sesión o cerrar sesión, se requiere una recarga de página completa.
La aplicación de ejemplo solo proporciona un nombre de usuario y un correo electrónico con fines de demostración. No incluye tokens que se autentican en el servidor al realizar solicitudes posteriores, que funcionan por separado mediante un cookie que se incluye en solicitudes HttpClient al servidor.
Proyecto de API web de back-end (MinimalApiJwt
)
El proyecto MinimalApiJwt
es una API web de back-end para varios proyectos de front-end. El proyecto configura un punto de conexión de API mínima para datos meteorológicos. Las solicitudes del proyecto del lado servidor de la Blazor Web App (BlazorWebAppOidc
) se redirigen mediante proxy al proyecto MinimalApiJwt
.
Configuración
Configura el proyecto en JwtBearerOptions de la llamada AddJwtBearer en el archivo del proyecto Program
:
Audience: establece la audiencia de cualquier token de OpenID Connect recibido.
En Entra o Azure Portal: haga coincidir el valor con solo la ruta de acceso del URI del id. de aplicación configurado al agregar el ámbito
Weather.Get
en Exponer una API:jwtOptions.Audience = "{APP ID URI}";
Ejemplo:
URI de identificador de aplicación (
{APP ID URI}
):https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
:- Nombre del directorio (
{DIRECTORY NAME}
):contoso
- Identificador de aplicación (cliente) (
{CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
jwtOptions.Audience = "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444";
El ejemplo anterior pertenece a una aplicación registrada en un inquilino con un tipo de inquilino de AAD B2C. Si la aplicación está registrada en un inquilino ME-ID, el URI de identificador de aplicación es diferente, por lo que el público es diferente.
Ejemplo:
URI de identificador de aplicación (
{APP ID URI}
):api://{CLIENT ID}
con identificador de aplicación (cliente) ({CLIENT ID}
):00001111-aaaa-2222-bbbb-3333cccc4444
jwtOptions.Audience = "api://00001111-aaaa-2222-bbbb-3333cccc4444";
- Nombre del directorio (
Authority: establece la autoridad para realizar llamadas de OpenID Connect. Haz coincidir el valor con la autoridad configurada para el controlador OIDC en
BlazorWebAppOidc/Program.cs
:jwtOptions.Authority = "{AUTHORITY}";
Ejemplo:
Autoridad (
{AUTHORITY}
):https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/
(usa el id. de inquilinoaaaabbbb-0000-cccc-1111-dddd2222eeee
)jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
El ejemplo anterior pertenece a una aplicación registrada en un inquilino con un tipo de inquilino de AAD B2C. Si la aplicación está registrada en un inquilino ME-ID, la autoridad debe coincidir con el emisor (
iss
) del JWT devuelto por el proveedor de identity:jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
API mínima para datos meteorológicos
Punto de conexión de datos de previsión meteorológica segura en el archivo Program
del proyecto:
app.MapGet("/weather-forecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
}).RequireAuthorization();
El método de extensión RequireAuthorization requiere autorización para la definición de ruta. Para los controladores que agregues al proyecto, agrega el atributo [Authorize]
al controlador o la acción.
Agregar componentes que adoptan la representación interactiva del lado servidor
Dado que la aplicación usa la representación automática interactiva global a través del componente Routes
, los componentes individuales que especifican la representación interactiva del lado servidor (SSR interactivo, @rendermode InteractiveServer
) en su archivo de definición de componentes (.razor
) se colocan en la carpeta .Client
del proyecto Pages
.
Colocar componentes de SSR interactivos en el proyecto .Client
es contraintuitivo porque estos componentes solo se representan en el servidor.
Si colocas un componente de SSR interactivo en la carpeta del proyecto Components/Pages
de servidor, el componente se representa previamente con normalidad y se muestra brevemente en el explorador del usuario. Sin embargo, el enrutador del lado cliente no puede encontrar el componente, lo que resulta en última instancia en un error 404: no encontrado en el explorador.
Por lo tanto, coloca los componentes de SSR interactivos en la carpeta .Client
del proyecto Pages
.
Redireccionamiento a la página home al cerrar sesión
Cuando un usuario navega por la aplicación, el componente LogInOrOut
(Layout/LogInOrOut.razor
) establece un campo oculto para la dirección URL de retorno (ReturnUrl
) en el valor de la dirección URL actual (currentURL
). Cuando el usuario cierra la sesión de la aplicación, el proveedor de identity lo devuelve a la página desde la que cerró la sesión.
Si el usuario cierra sesión desde una página segura, se le devuelve a la misma página segura después de cerrar la sesión, solo para el envío de vuelta a través del proceso de autenticación. Este comportamiento es adecuado cuando los usuarios necesitan cambiar de cuenta con frecuencia. Sin embargo, una especificación de aplicación alternativa puede hacer que se devuelva al usuario a la página home de la aplicación o a otra página después del cierre de sesión. En el ejemplo siguiente se muestra cómo establecer la página home de la aplicación como la dirección URL de retorno para las operaciones de cierre de sesión.
Los cambios importantes en el componente LogInOrOut
se muestran en el ejemplo siguiente. No es necesario proporcionar un campo oculto para el ReturnUrl
conjunto en la home página en /
porque es la ruta de acceso predeterminada. IDisposable ya no se implementa. NavigationManager ya no se inserta. Se elimina todo el bloque @code
.
Layout/LogInOrOut.razor
:
@using Microsoft.AspNetCore.Authorization
<div class="nav-item px-3">
<AuthorizeView>
<Authorized>
<form action="authentication/logout" method="post">
<AntiforgeryToken />
<button type="submit" class="nav-link">
<span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
</span> Logout @context.User.Identity?.Name
</button>
</form>
</Authorized>
<NotAuthorized>
<a class="nav-link" href="authentication/login">
<span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span>
Login
</a>
</NotAuthorized>
</AuthorizeView>
</div>
Valor nonce criptográfico
Un valor nonce es un valor de cadena que asocia la sesión de un cliente con un token de identificador para mitigar los ataques de reproducción.
Si recibes un error del valor nonce durante el desarrollo y las pruebas de autenticación, usa una nueva sesión del explorador InPrivate o incógnito para cada ejecución de prueba, independientemente de lo pequeño que sea el cambio realizado en la aplicación o el usuario de prueba porque los datos de las cookie obsoletos pueden provocar un error del valor nonce. Para obtener más información, consulta la sección Cookies y datos del sitio.
No se requiere ni se usa un valor nonce cuando se intercambia un token de actualización para un nuevo token de acceso. En la aplicación de ejemplo, CookieOidcRefresher
(CookieOidcRefresher.cs
) establece deliberadamente OpenIdConnectProtocolValidator.RequireNonce en false
.
Roles de aplicación para aplicaciones no registradas con Microsoft Entra (ME-ID)
Esta sección pertenece a las aplicaciones que no usan Microsoft Entra ID (ME-ID) como proveedor de identity. Para las aplicaciones registradas con ME-ID, consulta la sección Roles de aplicación para aplicaciones registradas con Microsoft Entra (ME-ID).
Configura el tipo de notificación de rol (TokenValidationParameters.RoleClaimType) en OpenIdConnectOptions de Program.cs
:
oidcOptions.TokenValidationParameters.RoleClaimType = "{ROLE CLAIM TYPE}";
Para muchos proveedores de identity de OIDC, el tipo de notificación de rol es role
. Comprueba la documentación del proveedor de identity para obtener el valor correcto.
Reemplaza la clase UserInfo
del proyecto BlazorWebAppOidc.Client
por la siguiente:
UserInfo.cs
:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;
namespace BlazorWebAppOidc.Client;
// Add properties to this class and update the server and client
// AuthenticationStateProviders to expose more information about
// the authenticated user to the client.
public sealed class UserInfo
{
public required string UserId { get; init; }
public required string Name { get; init; }
public required string[] Roles { get; init; }
public const string UserIdClaimType = "sub";
public const string NameClaimType = "name";
private const string RoleClaimType = "role";
public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
new()
{
UserId = GetRequiredClaim(principal, UserIdClaimType),
Name = GetRequiredClaim(principal, NameClaimType),
Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
.ToArray(),
};
public ClaimsPrincipal ToClaimsPrincipal() =>
new(new ClaimsIdentity(
Roles.Select(role => new Claim(RoleClaimType, role))
.Concat([
new Claim(UserIdClaimType, UserId),
new Claim(NameClaimType, Name),
]),
authenticationType: nameof(UserInfo),
nameType: NameClaimType,
roleType: RoleClaimType));
private static string GetRequiredClaim(ClaimsPrincipal principal,
string claimType) =>
principal.FindFirst(claimType)?.Value ??
throw new InvalidOperationException(
$"Could not find required '{claimType}' claim.");
}
En este momento, los componentes Razor pueden adoptar la autorización basada en roles y directivas. Los roles de aplicación aparecen en notificaciones role
, una notificación por rol.
Roles de aplicación para aplicaciones registradas con Microsoft Entra (ME-ID)
Usa la guía de esta sección para implementar roles de aplicación, grupos de seguridad de ME-ID y roles de cuenta predefinida de administrador de ME-ID para aplicaciones que usan Microsoft Entra ID (ME-ID).
El enfoque descrito en esta sección configura ME-ID para enviar grupos y roles en el encabezado cookie de autenticación. Cuando los usuarios solo son miembros de unos pocos grupos de seguridad y roles, el siguiente enfoque debe funcionar para la mayoría de las plataformas de hospedaje sin tener un problema en el que los encabezados son demasiado largos, por ejemplo, con el hospedaje de IIS que tiene un límite de longitud de encabezado predeterminado de 16 KB (MaxRequestBytes
). Si la longitud del encabezado es un problema debido a la pertenencia a grupos o roles elevados, se recomienda no seguir las instrucciones de esta sección en favor de implementar Microsoft Graph para obtener los grupos y roles de un usuario de ME-ID por separado, un enfoque que no infla el tamaño de la autenticación cookie. Para obtener más información, consulta Solicitud incorrecta- Solicitud demasiado larga - Servidor IIS (dotnet/aspnetcore
#57545).
Configura el tipo de notificación de rol (TokenValidationParameters.RoleClaimType) en OpenIdConnectOptions de Program.cs
. Establece el valor en roles
:
oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
Aunque no se pueden asignar roles a grupos sin una cuenta de Microsoft Entra ID Premium, sí se pueden asignar roles a usuarios y recibir una notificación para usuarios con una cuenta de Azure estándar. Las instrucciones de esta sección no requieren una cuenta ME-ID Premium.
Al trabajar con el directorio predeterminado, sigue las instrucciones de Incorporación de roles de aplicación a una aplicación y recibirlos en el token (documentación de ME-ID) para configurar y asignar los roles. Si no estás trabajando con el directorio predeterminado, edita el manifiesto de la aplicación en Azure Portal para establecer manualmente los roles de la aplicación en la entrada appRoles
del archivo de manifiesto. Para obtener más información, consulta Configuración de notificación de rol (documentación de ME-ID).
Los grupos de seguridad de Azure de un usuario llegan a notificaciones groups
y las asignaciones de rol Administrador de ME-ID integradas de un usuario llegan a notificaciones de id. conocidos (wids
). Los valores de ambos tipos de notificación son GUID. Cuando la aplicación las recibe, estas notificaciones se pueden usar para establecer la autorización de roles y directivas en los componentes Razor.
En el manifiesto de la aplicación de Azure Portal, establece el atributo groupMembershipClaims
en All
. Un valor de All
da como resultado que ME-ID envíe todos los grupos de seguridad o de distribución (notificaciones groups
) y los roles (notificaciones wids
) del usuario que ha iniciado sesión. Para establecer el atributo groupMembershipClaims
:
- Abre el registro de la aplicación en Azure Portal.
- Selecciona Administrar>Manifiesto en la barra lateral.
- Busca el atributo
groupMembershipClaims
. - Establece el valor en
All
("groupMembershipClaims": "All"
). - Selecciona el botón Guardar.
Reemplaza la clase UserInfo
del proyecto BlazorWebAppOidc.Client
por la siguiente:
UserInfo.cs
:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;
namespace BlazorWebAppOidc.Client;
// Add properties to this class and update the server and client
// AuthenticationStateProviders to expose more information about
// the authenticated user to the client.
public sealed class UserInfo
{
public required string UserId { get; init; }
public required string Name { get; init; }
public required string[] Roles { get; init; }
public required string[] Groups { get; init; }
public required string[] Wids { get; init; }
public const string UserIdClaimType = "sub";
public const string NameClaimType = "name";
private const string RoleClaimType = "roles";
private const string GroupsClaimType = "groups";
private const string WidsClaimType = "wids";
public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
new()
{
UserId = GetRequiredClaim(principal, UserIdClaimType),
Name = GetRequiredClaim(principal, NameClaimType),
Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
.ToArray(),
Groups = principal.FindAll(GroupsClaimType).Select(c => c.Value)
.ToArray(),
Wids = principal.FindAll(WidsClaimType).Select(c => c.Value)
.ToArray(),
};
public ClaimsPrincipal ToClaimsPrincipal() =>
new(new ClaimsIdentity(
Roles.Select(role => new Claim(RoleClaimType, role))
.Concat(Groups.Select(role => new Claim(GroupsClaimType, role)))
.Concat(Wids.Select(role => new Claim(WidsClaimType, role)))
.Concat([
new Claim(UserIdClaimType, UserId),
new Claim(NameClaimType, Name),
]),
authenticationType: nameof(UserInfo),
nameType: NameClaimType,
roleType: RoleClaimType));
private static string GetRequiredClaim(ClaimsPrincipal principal,
string claimType) =>
principal.FindFirst(claimType)?.Value ??
throw new InvalidOperationException(
$"Could not find required '{claimType}' claim.");
}
En este momento, los componentes Razor pueden adoptar la autorización basada en roles y directivas:
- Los roles de aplicación aparecen en notificaciones
roles
, una notificación por rol. - Los grupos de seguridad aparecen en notificaciones
groups
, una notificación por grupo. Los GUID del grupo de seguridad aparecen en Azure Portal al crear un grupo de seguridad y se muestran al seleccionar Identity>Información general>Grupos>Vista. - Los roles de administrador de ME-ID integrados aparecen en notificaciones
wids
, una notificación por rol. La notificaciónwids
con un valor deb79fbf4d-3ef9-4689-8143-76b194e85509
siempre se envía mediante ME-ID para las cuentas del inquilino que no son de invitado y no hace referencia a un rol Administrador. Los GUID de rol Administrador (id. de plantilla de rol) aparecen en Azure Portal al seleccionar Roles y administradores, seguidos de los puntos suspensivos (…) >Descripción para el rol indicado. Los id. de plantilla de rol también aparecen en roles integrados de Microsoft Entra (documentación de Entra).
Solución de problemas
Registro
La aplicación de servidor es una aplicación estándar ASP.NET Core. Consulta la guía de registro de ASP.NET Core para habilitar un nivel de registro inferior en la aplicación de servidor.
Para habilitar el registro de depuración o rastreo para la autenticación de Blazor WebAssembly, consulta la sección Registro de autenticación del lado del cliente del Registro de Blazor de ASP.NET Core con el selector de versión del artículo establecido en ASP.NET Core 7.0 o posterior.
Errores comunes
Error de configuración de la aplicación o del proveedor de Identity (IP)
Los errores más comunes se deben a una configuración incorrecta. Estos son algunos ejemplos:
- En función de los requisitos del escenario, la disponibilidad o no de una autoridad, una instancia, un identificador o dominio de inquilino, un identificador de cliente o un URI de redireccionamiento, o bien que estos no elementos no sean correctos, impide a una aplicación autenticar clientes.
- Los ámbitos de solicitud incorrectos impiden a los clientes acceder a los puntos de conexión de la API web del servidor.
- Faltan permisos de la API de servidor o estos son incorrectos, lo cual impide a los clientes acceder a los puntos de conexión de API web.
- Ejecutar la aplicación en un puerto diferente al configurado en el URI de redirección del registro de aplicación de la IP. Ten en cuenta que no se requiere ningún puerto para Microsoft Entra ID y una aplicación que se ejecute en una dirección de pruebas de desarrollo
localhost
, pero la configuración del puerto de la aplicación y el puerto en el que se ejecuta la aplicación deben coincidir para las direcciones que no seanlocalhost
.
La cobertura de configuración de este artículo muestra ejemplos de la configuración correcta. Comprueba cuidadosamente la configuración que busca la aplicación y la configuración incorrecta de IP.
Si la configuración parece correcta:
Analiza los registros de la aplicación.
Examina el tráfico de red entre la aplicación cliente y la de servidor, o la dirección IP con las herramientas de desarrollo del explorador. A menudo, la aplicación de servidor o la dirección IP devuelve al cliente un mensaje de error exacto o un mensaje con una pista sobre la causa del problema. En los siguientes artículos encontrarás instrucciones sobre las herramientas de desarrollo:
- Google Chrome (documentación de Google)
- Microsoft Edge
- Mozilla Firefox (documentación de Mozilla)
El equipo de documentación responde a los comentarios y los errores en los artículos (abre una incidencia en la sección de comentarios de esta página), pero no puede proporcionar soporte técnico para el producto. Existen varios foros de soporte técnico públicos que ayudan a solucionar los problemas de una aplicación. Se recomienda lo siguiente:
Microsoft no posee ni controla ninguno de los foros anteriores.
Respecto a los informes de errores del marco que no son de seguridad ni confidenciales, o que no se pueden reproducir, abre una incidencia con la unidad de producto ASP.NET Core. No abras una incidencia con la unidad de producto hasta que hayas investigado exhaustivamente su causa y no puedas resolverlo por tu cuenta o con la ayuda de la comunidad en un foro de soporte técnico público. La unidad de producto no puede solucionar problemas de aplicaciones individuales cuyo funcionamiento se haya interrumpido debido a errores de configuración o casos de uso sencillos que involucren servicios de terceros. Si un informe es confidencial o delicado por naturaleza o describe un posible error de seguridad en el producto que los ciberdelincuentes puedan aprovechar, consulta Informes de problemas de seguridad y errores (repositorio de GitHub
dotnet/aspnetcore
).Cliente no autorizado para ME-ID
Información: Error de autorización de Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]. No se cumplen estos requisitos: DenyAnonymousAuthorizationRequirement: se requiere un usuario autenticado.
Error de devolución de llamada de inicio de sesión de ME-ID:
- Error:
unauthorized_client
- Descripción:
AADB2C90058: The provided application is not configured to allow public clients.
Para resolver el error:
- En Azure Portal, accede al manifiesto de la aplicación.
- Establece el atributo
allowPublicClient
ennull
otrue
.
- Error:
Cookies y datos de sitios
Las cookies y los datos de sitios pueden persistir durante las actualizaciones de la aplicación e interferir con las pruebas y la solución de problemas. Borra los elementos siguientes al realizar cambios en el código de la aplicación, cambios en la cuenta de usuario con el proveedor o cuando el proveedor modifique la configuración de la aplicación:
- Cookies de inicio de sesión de usuario
- Cookies de aplicación
- Datos de sitios almacenados y en caché
El enfoque siguiente sirve para evitar que las cookies persistentes y los datos de sitios interfieran con las pruebas y la solución de problemas:
- Configuración de un explorador
- Usa un explorador para las pruebas, y configúralo para que elimine todas las cookies y los datos del sitio cada vez que se cierre.
- Asegúrate de que el explorador se cierra manualmente o mediante el IDE siempre que se produzca cualquier cambio en la aplicación, el usuario de prueba o la configuración del proveedor.
- Usa un comando personalizado para abrir un explorador en el modo incógnito o privado en Visual Studio:
- Abre el cuadro de diálogo Examinar con mediante el botón Ejecutar de Visual Studio.
- Selecciona el botón Agregar.
- Proporciona la ruta de acceso al explorador en el campo Programa. Las siguientes rutas de acceso del archivo ejecutable son ubicaciones de instalación típicas para Windows 10. Si el explorador está instalado en una ubicación diferente o no usa Windows 10, proporciona la ruta de acceso al archivo ejecutable del explorador.
- Microsoft Edge:
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
- Google Chrome:
C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
- Mozilla Firefox:
C:\Program Files\Mozilla Firefox\firefox.exe
- Microsoft Edge:
- En el campo Argumentos, proporciona la opción de línea de comandos que utiliza el explorador para abrirse en el modo incógnito o privado. Algunos exploradores requieren la dirección URL de la aplicación.
- Microsoft Edge: Usa
-inprivate
. - Google Chrome: usa
--incognito --new-window {URL}
, donde el marcador de posición{URL}
es la dirección URL que se va a abrir (por ejemplo,https://localhost:5001
). - Mozilla Firefox: usa
-private -url {URL}
, donde el marcador de posición{URL}
es la dirección URL que se va a abrir (por ejemplo,https://localhost:5001
).
- Microsoft Edge: Usa
- Proporciona un nombre en el campo Nombre descriptivo. Por ejemplo:
Firefox Auth Testing
. - Selecciona el botón Aceptar.
- Para evitar tener que seleccionar el perfil de explorador para cada iteración de pruebas con una aplicación, establece el perfil como predeterminado con el botón Establecer como predeterminado.
- Asegúrate de que el explorador se cierra mediante el IDE siempre que se produzca cualquier cambio en la aplicación, el usuario de prueba o la configuración del proveedor.
Actualizaciones de aplicaciones
Una aplicación en funcionamiento deja de ejecutarse inmediatamente después de actualizar el SDK de .NET Core en la máquina de desarrollo o de cambiar las versiones del paquete en la aplicación. En algunos casos, los paquetes incoherentes pueden interrumpir una aplicación al realizar actualizaciones importantes. La mayoría de estos problemas puede corregirse siguiendo estas instrucciones:
- Borra las memorias caché del paquete NuGet del sistema local ejecutando
dotnet nuget locals all --clear
desde un shell de comandos. - Elimina las carpetas
bin
yobj
del proyecto. - Restaura el proyecto y vuelve a compilarlo.
- Elimina todos los archivos de la carpeta de implementación del servidor antes de volver a implementar la aplicación.
Nota
No se pueden usar versiones de paquetes que no sean compatibles con la plataforma de destino de la aplicación. Para obtener información sobre un paquete, usa la galería de NuGet o el explorador de paquetes FuGet.
Ejecución de la aplicación Server
Al probar y solucionar problemas de una Blazor Web App, asegúrate de que ejecutas la aplicación desde el proyecto del servidor.
Inspección del usuario
El siguiente componente UserClaims
se puede usar directamente en las aplicaciones, o bien servir como base para una mayor personalización.
UserClaims.razor
:
@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
<PageTitle>User Claims</PageTitle>
<h1>User Claims</h1>
@if (claims.Any())
{
<ul>
@foreach (var claim in claims)
{
<li><b>@claim.Type:</b> @claim.Value</li>
}
</ul>
}
@code {
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthState == null)
{
return;
}
var authState = await AuthState;
claims = authState.User.Claims;
}
}
Recursos adicionales
- Repositorio GitHub de
AzureAD/microsoft-identity-web
: guía útil sobre la implementación de Microsoft Identity Web para Microsoft Entra ID y Azure Active Directory B2C para aplicaciones ASP.NET Core, incluidos vínculos a aplicaciones de ejemplo y documentación relacionada de Azure. Actualmente, la documentación de Azure no aborda explícitamente los objetos Blazor Web App, pero la configuración de un objeto Blazor Web App para ME-ID y el hospedaje de Azure es igual que para cualquier aplicación web de ASP.NET Core. AuthenticationStateProvider
del ssDE- Administrar el estado de autenticación en Blazor Web App
- Actualizar token durante la solicitud HTTP en el servidor interactivo Blazor con OIDC (
dotnet/aspnetcore
#55213)