Protección de una aplicación hospedada Blazor WebAssembly de ASP.NET Core con Identity Server
En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa Duende Identity Server para autenticar usuarios y llamadas API.
Importante
Duende Software puede requerir que pague una tarifa de licencia para el uso en producción de Duende Identity Server. Para obtener más información, vea Migración de ASP.NET Core 5.0 a 6.0.
Nota
Para configurar una aplicación Blazor WebAssembly independiente u hospedada para que use una instancia de Identity Server externa existente, siga las instrucciones de Protección de una aplicación independiente Blazor WebAssembly de ASP.NET Core con la biblioteca de autenticación.
Para crear un nuevo proyecto de Blazor WebAssembly con un mecanismo de autenticación:
Cree un nuevo proyecto.
Elija la plantilla Aplicación de Blazor WebAssembly . Seleccione Siguiente.
Proporcione un Nombre de proyecto sin usar guiones (vea la ADVERTENCIA siguiente). Confirme que la Ubicación es correcta. Seleccione Next (Siguiente).
Advertencia
Evite usar guiones (
-) en el nombre del proyecto 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).En el cuadro de diálogo Información adicional, seleccione Cuentas individuales como Tipo de autenticación para almacenar usuarios dentro de la aplicación mediante el sistema Identity de ASP.NET Core.
Active la casilla ASP.NET Core hospedado.
Configuración de la aplicación Server
En las siguientes secciones se describen algunas adiciones al proyecto cuando se incluye compatibilidad con la autenticación.
Clase Startup
La clase Startup tiene las siguientes adiciones.
En
Program.cs:ASP.NET Core Identity:
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();IdentityServer con un método auxiliar AddApiAuthorization adicional que configura convenciones de ASP.NET Core predeterminadas por encima de IdentityServer:
builder.Services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();Autenticación con un método auxiliar AddIdentityServerJwt adicional que configura la aplicación para validar los tokens JWT generados por IdentityServer:
builder.Services.AddAuthentication() .AddIdentityServerJwt();
En
Program.cs:El middleware IdentityServer expone los puntos de conexión de OpenID Connect (OIDC):
app.UseIdentityServer();El middleware Authentication es responsable de validar las credenciales de solicitud y de configurar el usuario en el contexto de la solicitud:
app.UseAuthentication();El middleware Authorization habilita capacidades de autorización:
app.UseAuthorization();
Azure App Service en Linux
Al realizar una implementación en Azure App Service en Linux, especifique el emisor de forma explícita. Para obtener más información, vea Introducción a la autenticación de aplicaciones de página única en ASP.NET Core.
AddApiAuthorization
El método auxiliar AddApiAuthorization configura Identity Server en escenarios de ASP.NET Core. Identity Server es un marco eficaz y extensible que sirve para abordar los problemas de seguridad de las aplicaciones. IdentityServer expone las complejidades innecesarias en los escenarios más comunes. En consecuencia, se proporciona un conjunto de convenciones y opciones de configuración que consideramos un buen punto de partida. Cuando sus necesidades de autenticación cambien, tendrá a su disposición toda la eficacia de IdentityServer para personalizar la autenticación para adaptarse a los requisitos de una aplicación.
AddIdentityServerJwt
El método auxiliar AddIdentityServerJwt configura un esquema de directiva para la aplicación como el controlador de autenticación predeterminado. La directiva está configurada para permitir que Identity controle todas las solicitudes enrutadas a cualquier subruta en el espacio de dirección URL de Identity /Identity. JwtBearerHandler se encarga de todas las demás solicitudes. Este método también hace lo siguiente:
- Registra un recurso de API
{APPLICATION NAME}APIcon IdentityServer con un ámbito predeterminado de{APPLICATION NAME}API. - Configura el middleware de token de portador de JWT para validar los tokens emitidos por IdentityServer para la aplicación.
WeatherForecastController
En WeatherForecastController (Controllers/WeatherForecastController.cs), el atributo [Authorize] se aplica a la clase. Este atributo señala que, para acceder al recurso, el usuario debe estar autorizado en función de la directiva predeterminada. La directiva de autorización predeterminada está configurada para usar el esquema de autenticación predeterminado, que AddIdentityServerJwt configura. El método auxiliar configura JwtBearerHandler como el controlador predeterminado de las solicitudes a la aplicación.
ApplicationDbContext
En ApplicationDbContext (Data/ApplicationDbContext.cs), DbContext extiende ApiAuthorizationDbContext<TUser> para incluir el esquema de IdentityServer. La clase ApiAuthorizationDbContext<TUser> se deriva de la clase IdentityDbContext.
Para obtener el control total del esquema de la base de datos, herede de una de las clases DbContext de Identity disponibles y configure el contexto para incluir el esquema de Identity llamando a builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) en el método OnModelCreating.
OidcConfigurationController
En OidcConfigurationController (Controllers/OidcConfigurationController.cs), el punto de conexión del cliente se aprovisiona para proporcionar parámetros de OIDC.
Configuración de la aplicación
En el archivo de configuración de la aplicación (appsettings.json), en la raíz del proyecto, la sección IdentityServer describe la lista de clientes configurados. En el siguiente ejemplo hay un solo cliente, cuyo nombre corresponde al nombre de la aplicación y se asigna por convención al parámetro ClientId de OAuth. El perfil señala el tipo de aplicación que se está configurando. El perfil se usa internamente para controlar las convenciones que simplifican el proceso de configuración del servidor.
"IdentityServer": {
"Clients": {
"{APP ASSEMBLY}.Client": {
"Profile": "IdentityServerSPA"
}
}
}
El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).
Configuración de la aplicación Client
Paquete de autenticación
Cuando una aplicación se crea para usar cuentas de usuario individuales (Individual), dicha aplicación recibe automáticamente una referencia de paquete del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication en el archivo de proyecto de la aplicación. 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.AspNetCore.Components.WebAssembly.Authentication"
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.
Configuración de HttpClient
En Program.cs, hay configurada una instancia de HttpClient ({APP ASSEMBLY}.ServerAPI) con nombre para proporcionar instancias de HttpClient que incluyen tokens de acceso al realizar solicitudes a la API de servidor:
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).
Nota
Si va a configurar una aplicación Blazor WebAssembly para usar una instancia de Identity Server existente que no forma parte de una solución hospedada por Blazor, cambie el registro de la dirección base HttpClient de IWebAssemblyHostEnvironment.BaseAddress (builder.HostEnvironment.BaseAddress) a la dirección URL del punto de conexión de autorización de API de la aplicación de servidor.
Compatibilidad con autorización de API
La compatibilidad para autenticar usuarios se incluye en el contenedor de servicios con el método de extensión proporcionado dentro del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication. Este método configura los servicios necesarios para que la aplicación interactúe con el sistema de autorización existente.
builder.Services.AddApiAuthorization();
La configuración de la aplicación se carga por convención de forma predeterminada desde _configuration/{client-id}. Por convención, el identificador de cliente se establece en el nombre de ensamblado de la aplicación. Esta dirección URL se puede cambiar para que apunte a un punto de conexión aparte llamando a la sobrecarga con opciones.
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.AspNetCore.Components.WebAssembly.Authentication/
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
RedirectToLoginadministra 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
maindel 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 ramarelease/5.0para 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 vínculo a la página de perfil de usuario en ASP.NET Core Identity.
- Proporciona un botón para cerrar la sesión de la aplicación.
- En el caso de los usuarios anónimos:
- Ofrece la opción de registrarse.
- Ofrece la opción de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
<a href="authentication/profile">Hello, @context.User.Identity.Name!</a>
<button class="nav-link btn btn-link" @onclick="BeginSignOut">
Log out
</button>
</Authorized>
<NotAuthorized>
<a href="authentication/register">Register</a>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code {
private async Task BeginSignOut(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:
- Se proporciona mediante el paquete
Microsoft.AspNetCore.Components.WebAssembly.Authentication. - Administra la realización de las acciones adecuadas en cada fase de autenticación.
@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.
Notificaciones name y role con autorización de API
Fábrica de usuario personalizada
En la aplicación Client , cree una fábrica de usuario personalizada. Identity Server envía varios roles como una matriz JSON en una sola notificación role. Se envía un único rol como un valor de cadena en la notificación. La fábrica crea una notificación role individual por cada uno de los roles del usuario.
CustomUserFactory.cs:
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomUserFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
En la aplicación Client , registre la fábrica en Program.cs:
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<CustomUserFactory>();
En la aplicación Server , llame a AddRoles en el generador de Identity, que agrega servicios relativos a roles:
using Microsoft.AspNetCore.Identity;
...
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Configuración de Identity Server
Siga uno de estos procedimientos:
Opciones de autorización de API
En la aplicación Server :
- Configure Identity Server para colocar las notificaciones
nameyroleen el token de identificador y el token de acceso. - Evite la asignación predeterminada de roles en el controlador de token JWT.
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
...
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Servicio de perfil
En la aplicación Server , cree una implementación ProfileService.
ProfileService.cs:
using IdentityModel;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Services;
using System.Threading.Tasks;
public class ProfileService : IProfileService
{
public ProfileService()
{
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
context.IssuedClaims.AddRange(nameClaim);
var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
context.IssuedClaims.AddRange(roleClaims);
await Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
await Task.CompletedTask;
}
}
En la aplicación Server , registre el servicio de perfil en Program.cs:
using Duende.IdentityServer.Services;
...
builder.Services.AddTransient<IProfileService, ProfileService>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Uso de mecanismos de autorización
En la aplicación Client , los métodos de autorización de componentes son funcionales en este momento. Cualquiera de los mecanismos de autorización de los componentes puede usar un rol para autorizar al usuario:
Componente
AuthorizeView(ejemplo:<AuthorizeView Roles="admin">)Directiva de atributo
[Authorize](AuthorizeAttribute) (ejemplo:@attribute [Authorize(Roles = "admin")])Lógica de procedimientos (ejemplo:
if (user.IsInRole("admin")) { ... })Se admiten pruebas de rol múltiple:
if (user.IsInRole("admin") && user.IsInRole("developer")) { ... }
User.Identity.Name se rellena en la aplicación Client con el nombre de usuario del usuario, que suele ser su dirección de correo electrónico de inicio de sesión.
UserManager y SignInManager
Establezca el tipo de notificaciones de identificador de usuario cuando una aplicación de servidor requiera:
- UserManager<TUser> o SignInManager<TUser> en un punto de conexión de API.
- Detalles de IdentityUser, como el nombre de usuario, la dirección de correo electrónico o la hora de finalización del bloqueo.
En Startup.ConfigureServices:
using System.Security.Claims;
...
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
El elemento WeatherForecastController siguiente registra la propiedad UserName cuando se llama al método Get:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using {APP NAMESPACE}.Server.Models;
using {APP NAMESPACE}.Shared;
namespace {APP NAMESPACE}.Server.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly UserManager<ApplicationUser> userManager;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm",
"Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger,
UserManager<ApplicationUser> userManager)
{
this.logger = logger;
this.userManager = userManager;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
var rng = new Random();
var user = await userManager.GetUserAsync(User);
if (user != null)
{
logger.LogInformation($"User.Identity.Name: {user.UserName}");
}
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Host en Azure App Service con un dominio personalizado y un certificado
En la guía siguiente se explica:
- Cómo implementar una aplicación de Blazor WebAssembly hospedada con Identity Server para Azure App Service con un dominio personalizado.
- Cómo crear y usar un certificado TLS para la comunicación del protocolo HTTPS con exploradores. Aunque la guía se centra en el uso del certificado con un dominio personalizado, la guía se aplica igualmente al uso de un dominio predeterminado de aplicaciones de Azure, por ejemplo
contoso.azurewebsites.net.
En este escenario de hospedaje, no use el mismo certificado para la clave de firma de tokens de Identity Server y la comunicación segura HTTPS del sitio con exploradores:
- Usar certificados diferentes para estos dos requisitos es una buena práctica de seguridad porque aísla claves privadas para cada propósito.
- Los certificados TLS para la comunicación con los exploradores se administran de forma independiente sin afectar a la firma de tokens de Identity Server.
- Cuando Azure Key Vault proporciona un certificado a una aplicación de App Service para el enlace de dominio personalizado, Identity Server no puede obtener el mismo certificado de Azure Key Vault para la firma de tokens. Aunque es posible configurar Identity Server para que use el mismo certificado TLS desde una ruta de acceso física, la colocación de los certificados de seguridad en el control de código fuente es una práctica inadecuada y debe evitarse en la mayoría de los casos.
En la siguiente guía, se crea un certificado autofirmado en Azure Key Vault únicamente para la firma de tokens de Identity Server. La configuración de Identity Server usa el certificado del almacén de claves mediante el almacén de certificados CurrentUser > My de la aplicación. Otros certificados que se usan para el tráfico HTTPS con dominios personalizados se crean y se configuran de forma independiente del certificado de firma de Identity Server.
Para configurar una aplicación, Azure App Service y Azure Key Vault para que hospeden con un dominio personalizado y HTTPS:
Cree un plan de App Service con un nivel de plan de
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.Cree un certificado PFX para la comunicación segura del explorador del sitio (protocolo HTTPS) con un nombre común del nombre de dominio completo (FQDN) del sitio que controla la organización (por ejemplo,
www.contoso.com). Cree el certificado con:- Usos de las claves
- Validación de firma digital (
digitalSignature) - Cifrado de claves (
keyEncipherment)
- Validación de firma digital (
- Usos mejorados/extendidos de las claves
- Autenticación de cliente (1.3.6.1.5.5.7.3.2)
- Autenticación del servidor (1.3.6.1.5.5.7.3.1)
Para crear el certificado, use uno de los métodos siguientes, o cualquier otra herramienta o servicio en línea adecuado:
Anote la contraseña, que se usará más adelante para importar el certificado en Azure Key Vault.
Para más información sobre los certificados de Azure Key Vault, consulte Azure Key Vault: Certificados.
- Usos de las claves
Cree una nueva instancia de Azure Key Vault o use un almacén de claves existente en su suscripción de Azure.
En el área Certificados del almacén de claves, importe el certificado del sitio PFX. Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.
En Azure Key Vault, genere un nuevo certificado autofirmado para la firma de tokens de Identity Server. Asigne al certificado un Nombre de certificado y un Firmante. El Firmante se especifica como
CN={COMMON NAME}, donde el marcador de posición{COMMON NAME}es el nombre común del certificado. El nombre común puede ser cualquier cadena alfanumérica. Por ejemplo,CN=IdentityServerSigninges un Firmante válido de certificado. Use la configuración predeterminada de la Configuración avanzada de directivas. Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.Vaya a Azure App Service en Azure Portal y cree un nuevo App Service con la siguiente configuración:
- Publicar establecido en
Code. - Pila en tiempo de ejecución establecido en el tiempo de ejecución de la aplicación.
- Para SKU y tamaño, confirme que el nivel de App Service sea
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.
- Publicar establecido en
Después de que Azure cree App Service, abra la Configuración de la aplicación y agregue una nueva configuración de aplicación que especifique las huellas digitales del certificado que se registraron anteriormente. La clave de configuración de la aplicación es
WEBSITE_LOAD_CERTIFICATES. Separe las huellas digitales de certificado en el valor de configuración de la aplicación con una coma, como se muestra en el ejemplo siguiente:- Clave:
WEBSITE_LOAD_CERTIFICATES - Valor:
57443A552A46DB...D55E28D412B943565,29F43A772CB6AF...1D04F0C67F85FB0B1
En Azure Portal, guardar la configuración de la aplicación es un proceso de dos pasos: Guarde la configuración de clave-valor de
WEBSITE_LOAD_CERTIFICATESy, después, seleccione el botón Guardar, en la parte superior de la hoja.- Clave:
Seleccione la configuración de TLS/SSL de la aplicación. Seleccione Certificados de clave privada (.pfx) . Use el proceso Importar certificado de Key Vault dos veces para importar el certificado del sitio para la comunicación HTTPS y el certificado autofirmado del sitio para la firma de tokens de Identity Server.
Vaya a la hoja Dominios personalizados. En el sitio web del registrador de dominios, use la dirección IP y el id. de verificación del dominio personalizado para configurar el dominio. Una configuración de dominio típica incluye:
- Un registro A con un host de
@y un valor de la dirección IP de Azure Portal. - Un registro TXT con un host de
asuidy el valor del id. de verificación generado por Azure y proporcionado por Azure Portal.
Asegúrese de guardar correctamente los cambios en el sitio web del registrador de dominios. Algunos sitios web del registrador requieren un proceso de dos pasos para guardar los registros de dominio: Uno o varios registros se guardan individualmente seguidos de la actualización del registro del dominio con un botón independiente.
- Un registro A con un host de
Vuelva a la hoja Dominios personalizados en Azure Portal. Seleccione Agregar dominio personalizado. Seleccione la opción Registro A. Proporcione el dominio y seleccione Validar. Si los registros de dominio son correctos y están propagados por Internet, el portal le permitirá seleccionar el botón Agregar dominio personalizado.
Los cambios en el registro de dominio pueden tardar unos días en propagarse entre los servidores de nombres de dominio (DNS) de Internet después de que el registrador de dominios los procese. Si los registros de dominio no se actualizan en un plazo de tres días laborables, confirme que los registros se han establecido correctamente con el registrador de dominios y póngase en contacto con el servicio de soporte técnico al cliente.
En la hoja Dominios personalizados, el ESTADO SSL del dominio está marcado como
Not Secure. Seleccione el vínculo Agregar enlaces. Seleccione el certificado HTTPS del sitio en el almacén de claves para el enlace de dominio personalizado.En Visual Studio, abra el archivo de configuración de la aplicación del proyecto Server (
appsettings.jsonoappsettings.Production.json). En la configuración de Identity Server, agregue la siguiente sección deKey. Especifique el Firmante del certificado autofirmado para la claveName. En el ejemplo siguiente, el nombre común del certificado asignado en el almacén de claves esIdentityServerSigning, lo que produce un Firmante deCN=IdentityServerSigning:"IdentityServer": { ... "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "CurrentUser", "Name": "CN=IdentityServerSigning" } },En Visual Studio, cree un perfil de publicación de Azure App Service para el proyecto Server. En la barra de menús, seleccione: Compilar > Publicar > Nuevo > Azure > Azure App Service (Windows o Linux). Cuando Visual Studio se conecta a una suscripción de Azure, puede establecer la Vista de recursos de Azure por Tipo de recurso. Navegue dentro de la lista Aplicación web para buscar la instancia de App Service de la aplicación y selecciónela. Seleccione Finalizar.
Cuando Visual Studio vuelve a la ventana Publicar, se detectan automáticamente el almacén de claves y las dependencias del servicio de base de datos SQL Server.
No se requiere ningún cambio de configuración en la configuración predeterminada para el servicio del almacén de claves.
Con fines de prueba, la base de datos SQLite local de una aplicación, que está configurada de forma predeterminada por la plantilla de Blazor, puede implementarse con la aplicación sin configuración adicional. La configuración de una base de datos diferente en producción para Identity Server está fuera del ámbito de este artículo. Para obtener más información, consulte los recursos de base de datos en los siguientes recursos:
Seleccione el enlace Editar debajo del nombre del perfil de implementación en la parte superior de la ventana. Cambie la dirección URL de destino a la dirección URL de dominio personalizada del sitio (por ejemplo,
https://www.contoso.com). Guarde la configuraciónPublique la aplicación. Visual Studio abre una ventana del explorador y solicita el sitio en su dominio personalizado.
La documentación de Azure contiene detalles adicionales sobre el uso de servicios de Azure y de dominios personalizados con enlace de TLS en App Service, incluida información sobre el uso de registros CNAME en lugar de registros A. Para obtener más información, vea los siguientes recursos:
- Documentación de App Service
- Tutorial: Asignación de un nombre DNS personalizado existente a Azure App Service
- Protección de un nombre DNS personalizado con un enlace TLS/SSL en Azure App Service
- Azure Key Vault
Se recomienda usar una nueva ventana del explorador en privado o en incógnito para cada ejecución de prueba de la aplicación después de un cambio en la aplicación, la configuración de la aplicación o los servicios de Azure en Azure Portal. Los elementos cookie persistentes de una serie de pruebas anterior pueden dar errores de autenticación o autorización al probar el sitio, incluso aunque la configuración del sitio sea correcta. Para obtener más información sobre cómo configurar Visual Studio para abrir una nueva ventana de explorador en privado o incógnito para cada serie de pruebas, consulte la sección Cookies y datos del sitio.
Cuando se cambia la configuración de App Service en Azure Portal, las actualizaciones suelen surtir efecto rápidamente, pero no son instantáneas. A veces, debe esperar un breve período para que App Service se reinicie y se aplique un cambio de configuración.
Si va a solucionar un problema de carga de certificados, ejecute el siguiente comando en un shell de comandos Kudu de PowerShell en Azure Portal. El comando proporciona una lista de certificados a los que la aplicación puede tener acceso desde el almacén de certificados de CurrentUser > My. La salida incluye firmantes de certificados y huellas digitales útiles al depurar una aplicación:
Get-ChildItem -path Cert:\CurrentUser\My -Recurse | Format-List DnsNameList, Subject, Thumbprint, EnhancedKeyUsageList
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:
- Google Chrome (documentación de Google)
- Microsoft Edge
- Mozilla Firefox (documentación de Mozilla)
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:
- En Azure Portal, acceda al manifiesto de la aplicación.
- Establezca el atributo
allowPublicClientennullotrue.
- Error:
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
- Microsoft Edge:
- 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).
- Microsoft Edge: Use
- 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:
- Borre las memorias caché del paquete NuGet del sistema local ejecutando
dotnet nuget locals all --cleardesde un shell de comandos. - Elimine las carpetas
binyobjdel proyecto. - Restaure el proyecto y vuelva a compilarlo.
- 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
- Implementación en Azure App Service
- Importación de un certificado de Key Vault (documentación de Azure)
- Otros escenarios de seguridad de Blazor WebAssembly en ASP.NET Core
- Solicitudes de API web no autenticadas o no autorizadas en una aplicación con un cliente predeterminado seguro
- Configuración de ASP.NET Core para trabajar con servidores proxy y equilibradores de carga; incluye instrucciones relativas a lo siguiente:
- Uso de middleware de encabezados reenviados para retener la información de esquemas HTTPS en servidores proxy y redes internas.
- Escenarios y casos de uso adicionales, incluidos la configuración manual de esquemas, los cambios en las rutas de las solicitudes para corregir el enrutamiento de las solicitudes y el reenvío de esquemas de solicitudes para Linux y proxies inversos que no sean de tipo IIS.
- Duende Identity Server
En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa IdentityServer para autenticar usuarios y llamadas API.
Nota
Para configurar una aplicación Blazor WebAssembly independiente u hospedada para que use una instancia de Identity Server externa existente, siga las instrucciones de Protección de una aplicación independiente Blazor WebAssembly de ASP.NET Core con la biblioteca de autenticación.
Para crear un nuevo proyecto de Blazor WebAssembly con un mecanismo de autenticación:
Cree un nuevo proyecto.
Elija la plantilla Aplicación de Blazor WebAssembly . Seleccione Siguiente.
Proporcione un Nombre de proyecto sin usar guiones (vea la ADVERTENCIA siguiente). Confirme que la Ubicación es correcta. Seleccione Next (Siguiente).
Advertencia
Evite usar guiones (
-) en el nombre del proyecto 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).En el cuadro de diálogo Información adicional, seleccione Cuentas individuales como Tipo de autenticación para almacenar usuarios dentro de la aplicación mediante el sistema Identity de ASP.NET Core.
Active la casilla ASP.NET Core hospedado.
Configuración de la aplicación Server
En las siguientes secciones se describen algunas adiciones al proyecto cuando se incluye compatibilidad con la autenticación.
Clase Startup
La clase Startup tiene las siguientes adiciones.
En
Startup.ConfigureServices:ASP.NET Core Identity:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();IdentityServer con un método auxiliar AddApiAuthorization adicional que configura convenciones de ASP.NET Core predeterminadas por encima de IdentityServer:
services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();Autenticación con un método auxiliar AddIdentityServerJwt adicional que configura la aplicación para validar los tokens JWT generados por IdentityServer:
services.AddAuthentication() .AddIdentityServerJwt();
En
Startup.Configure:El middleware IdentityServer expone los puntos de conexión de OpenID Connect (OIDC):
app.UseIdentityServer();El middleware Authentication es responsable de validar las credenciales de solicitud y de configurar el usuario en el contexto de la solicitud:
app.UseAuthentication();El middleware Authorization habilita capacidades de autorización:
app.UseAuthorization();
Azure App Service en Linux
Al realizar una implementación en Azure App Service en Linux, especifique el emisor de forma explícita. Para obtener más información, vea Introducción a la autenticación de aplicaciones de página única en ASP.NET Core.
AddApiAuthorization
El método auxiliar AddApiAuthorization configura IdentityServer en escenarios de ASP.NET Core. IdentityServer es un marco eficaz y extensible que sirve para abordar los problemas de seguridad de las aplicaciones. IdentityServer expone las complejidades innecesarias en los escenarios más comunes. En consecuencia, se proporciona un conjunto de convenciones y opciones de configuración que consideramos un buen punto de partida. Cuando sus necesidades de autenticación cambien, tendrá a su disposición toda la eficacia de IdentityServer para personalizar la autenticación para adaptarse a los requisitos de una aplicación.
AddIdentityServerJwt
El método auxiliar AddIdentityServerJwt configura un esquema de directiva para la aplicación como el controlador de autenticación predeterminado. La directiva está configurada para permitir que Identity controle todas las solicitudes enrutadas a cualquier subruta en el espacio de dirección URL de Identity /Identity. JwtBearerHandler se encarga de todas las demás solicitudes. Este método también hace lo siguiente:
- Registra un recurso de API
{APPLICATION NAME}APIcon IdentityServer con un ámbito predeterminado de{APPLICATION NAME}API. - Configura el middleware de token de portador de JWT para validar los tokens emitidos por IdentityServer para la aplicación.
WeatherForecastController
En WeatherForecastController (Controllers/WeatherForecastController.cs), el atributo [Authorize] se aplica a la clase. Este atributo señala que, para acceder al recurso, el usuario debe estar autorizado en función de la directiva predeterminada. La directiva de autorización predeterminada está configurada para usar el esquema de autenticación predeterminado, que AddIdentityServerJwt configura. El método auxiliar configura JwtBearerHandler como el controlador predeterminado de las solicitudes a la aplicación.
ApplicationDbContext
En ApplicationDbContext (Data/ApplicationDbContext.cs), DbContext extiende ApiAuthorizationDbContext<TUser> para incluir el esquema de IdentityServer. La clase ApiAuthorizationDbContext<TUser> se deriva de la clase IdentityDbContext.
Para obtener el control total del esquema de la base de datos, herede de una de las clases DbContext de Identity disponibles y configure el contexto para incluir el esquema de Identity llamando a builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) en el método OnModelCreating.
OidcConfigurationController
En OidcConfigurationController (Controllers/OidcConfigurationController.cs), el punto de conexión del cliente se aprovisiona para proporcionar parámetros de OIDC.
Configuración de la aplicación
En el archivo de configuración de la aplicación (appsettings.json), en la raíz del proyecto, la sección IdentityServer describe la lista de clientes configurados. En el siguiente ejemplo hay un solo cliente, cuyo nombre corresponde al nombre de la aplicación y se asigna por convención al parámetro ClientId de OAuth. El perfil señala el tipo de aplicación que se está configurando. El perfil se usa internamente para controlar las convenciones que simplifican el proceso de configuración del servidor.
"IdentityServer": {
"Clients": {
"{APP ASSEMBLY}.Client": {
"Profile": "IdentityServerSPA"
}
}
}
El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).
Configuración de la aplicación Client
Paquete de autenticación
Cuando una aplicación se crea para usar cuentas de usuario individuales (Individual), dicha aplicación recibe automáticamente una referencia de paquete del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication en el archivo de proyecto de la aplicación. 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.AspNetCore.Components.WebAssembly.Authentication"
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.
Configuración de HttpClient
En Program.cs, hay configurada una instancia de HttpClient ({APP ASSEMBLY}.ServerAPI) con nombre para proporcionar instancias de HttpClient que incluyen tokens de acceso al realizar solicitudes a la API de servidor:
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).
Nota
Si va a configurar una aplicación Blazor WebAssembly para usar una instancia de Identity Server existente que no forma parte de una solución hospedada por Blazor, cambie el registro de la dirección base HttpClient de IWebAssemblyHostEnvironment.BaseAddress (builder.HostEnvironment.BaseAddress) a la dirección URL del punto de conexión de autorización de API de la aplicación de servidor.
Compatibilidad con autorización de API
La compatibilidad para autenticar usuarios se incluye en el contenedor de servicios con el método de extensión proporcionado dentro del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication. Este método configura los servicios necesarios para que la aplicación interactúe con el sistema de autorización existente.
builder.Services.AddApiAuthorization();
La configuración de la aplicación se carga por convención de forma predeterminada desde _configuration/{client-id}. Por convención, el identificador de cliente se establece en el nombre de ensamblado de la aplicación. Esta dirección URL se puede cambiar para que apunte a un punto de conexión aparte llamando a la sobrecarga con opciones.
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.AspNetCore.Components.WebAssembly.Authentication/
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
RedirectToLoginadministra 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
maindel 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 ramarelease/5.0para 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 vínculo a la página de perfil de usuario en ASP.NET Core Identity.
- Proporciona un botón para cerrar la sesión de la aplicación.
- En el caso de los usuarios anónimos:
- Ofrece la opción de registrarse.
- Ofrece la opción de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
<a href="authentication/profile">Hello, @context.User.Identity.Name!</a>
<button class="nav-link btn btn-link" @onclick="BeginSignOut">
Log out
</button>
</Authorized>
<NotAuthorized>
<a href="authentication/register">Register</a>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code {
private async Task BeginSignOut(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:
- Se proporciona mediante el paquete
Microsoft.AspNetCore.Components.WebAssembly.Authentication. - Administra la realización de las acciones adecuadas en cada fase de autenticación.
@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.
Notificaciones name y role con autorización de API
Fábrica de usuario personalizada
En la aplicación Client , cree una fábrica de usuario personalizada. Identity Server envía varios roles como una matriz JSON en una sola notificación role. Se envía un único rol como un valor de cadena en la notificación. La fábrica crea una notificación role individual por cada uno de los roles del usuario.
CustomUserFactory.cs:
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomUserFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
En la aplicación Client , registre la fábrica en Program.cs:
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<CustomUserFactory>();
En la aplicación Server , llame a AddRoles en el generador de Identity, que agrega servicios relativos a roles:
using Microsoft.AspNetCore.Identity;
...
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Configuración de Identity Server
Siga uno de estos procedimientos:
Opciones de autorización de API
En la aplicación Server :
- Configure Identity Server para colocar las notificaciones
nameyroleen el token de identificador y el token de acceso. - Evite la asignación predeterminada de roles en el controlador de token JWT.
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
...
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Servicio de perfil
En la aplicación Server , cree una implementación ProfileService.
ProfileService.cs:
using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Services;
using System.Threading.Tasks;
public class ProfileService : IProfileService
{
public ProfileService()
{
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
context.IssuedClaims.AddRange(nameClaim);
var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
context.IssuedClaims.AddRange(roleClaims);
await Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
await Task.CompletedTask;
}
}
En la aplicación Server , registre el servicio de perfil en Startup.ConfigureServices:
using IdentityServer4.Services;
...
services.AddTransient<IProfileService, ProfileService>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Uso de mecanismos de autorización
En la aplicación Client , los métodos de autorización de componentes son funcionales en este momento. Cualquiera de los mecanismos de autorización de los componentes puede usar un rol para autorizar al usuario:
Componente
AuthorizeView(ejemplo:<AuthorizeView Roles="admin">)Directiva de atributo
[Authorize](AuthorizeAttribute) (ejemplo:@attribute [Authorize(Roles = "admin")])Lógica de procedimientos (ejemplo:
if (user.IsInRole("admin")) { ... })Se admiten pruebas de rol múltiple:
if (user.IsInRole("admin") && user.IsInRole("developer")) { ... }
User.Identity.Name se rellena en la aplicación Client con el nombre de usuario del usuario, que suele ser su dirección de correo electrónico de inicio de sesión.
UserManager y SignInManager
Establezca el tipo de notificaciones de identificador de usuario cuando una aplicación de servidor requiera:
- UserManager<TUser> o SignInManager<TUser> en un punto de conexión de API.
- Detalles de IdentityUser, como el nombre de usuario, la dirección de correo electrónico o la hora de finalización del bloqueo.
En Startup.ConfigureServices:
using System.Security.Claims;
...
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
El elemento WeatherForecastController siguiente registra la propiedad UserName cuando se llama al método Get:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using {APP NAMESPACE}.Server.Models;
using {APP NAMESPACE}.Shared;
namespace {APP NAMESPACE}.Server.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly UserManager<ApplicationUser> userManager;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm",
"Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger,
UserManager<ApplicationUser> userManager)
{
this.logger = logger;
this.userManager = userManager;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
var rng = new Random();
var user = await userManager.GetUserAsync(User);
if (user != null)
{
logger.LogInformation($"User.Identity.Name: {user.UserName}");
}
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Escenarios de firma de tokens con Azure App Service
Se cubren dos escenarios. Siga las instrucciones de una de las secciones siguientes:
- Hospedaje en Azure App Service con firma automática de tokens y seguridad de claves de protección de datos mediante Azure Key Vault
- Hospedaje en Azure App Service con firma de tokens de certificado
Hospedaje en Azure App Service con firma automática de tokens y seguridad de claves de protección de datos mediante Azure Key Vault
En las instrucciones de esta sección se explica lo siguiente:
- Cómo implementar una aplicación de Blazor WebAssembly hospedada con Identity Server para Azure App Service.
- Cómo usar la firma automática de tokens Identity Server con seguridad de claves de protección de datos protegida por Azure Key Vault.
Nota
Para crear e implementar un certificado TLS para la comunicación del protocolo HTTPS después de seguir las instrucciones de esta sección, consulte la sección Uso de un dominio personalizado y un certificado TLS para la comunicación del protocolo HTTPS en Azure App Service de este artículo.
Cree un plan de App Service.
Nota
Se requiere un plan de App Service con un nivel de plan de
Basic B1o superior si también tiene previsto usar uno o varios dominios personalizados con la aplicación.Cree una nueva instancia de Azure Key Vault o use un almacén de claves existente en su suscripción de Azure.
Vaya a Azure App Service en Azure Portal y cree un nuevo App Service con la siguiente configuración:
- Publicar establecido en
Code. - Pila en tiempo de ejecución establecido en el tiempo de ejecución de la aplicación.
- Para SKU y tamaño, confirme que el nivel de App Service sea
Basic B1o superior si también tiene previsto usar un dominio personalizado. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.
- Publicar establecido en
Configure la aplicación para que use la firma automática de tokens y Azure Key Vault para almacenar y proteger las claves de protección de datos de ASP.NET Core:
La firma de tokens Identity Server es automática de forma predeterminada. Identity Server también usa la protección de datos de ASP.NET Core de forma predeterminada. No se requiere ninguna configuración en la aplicación para estas características. Para obtener más información, vea Automatic key management (Duende Software documentation) [Administración automática de claves (documentación de Duende Software)].
Se requiere configuración para que la aplicación utilice Azure Key Vault para almacenar y proteger las claves usadas para la protección de datos de ASP.NET Core. Use las instrucciones de los recursos de documentación de ASP.NET Core siguientes para configurar las características necesarias:
En Visual Studio, cree un perfil de publicación de Azure App Service para el proyecto Server. En la barra de menús, seleccione: Compilar > Publicar > Nuevo > Azure > Azure App Service (Windows o Linux). Cuando Visual Studio se conecta a una suscripción de Azure, puede establecer la Vista de recursos de Azure por Tipo de recurso. Navegue dentro de la lista Aplicación web para buscar la instancia de App Service de la aplicación y selecciónela. Seleccione Finalizar.
Cuando Visual Studio vuelve a la ventana Publicar, se detectan automáticamente el almacén de claves y las dependencias del servicio de base de datos SQL Server.
No se requiere ningún cambio de configuración en la configuración predeterminada para el servicio del almacén de claves.
Con fines de prueba, la base de datos SQLite local de una aplicación, que está configurada de forma predeterminada por la plantilla de Blazor, puede implementarse con la aplicación sin configuración adicional. La configuración de una base de datos diferente en producción para Identity Server está fuera del ámbito de este artículo. Para obtener más información, consulte los recursos de base de datos en los siguientes recursos:
Publique la aplicación. Visual Studio abre una ventana del explorador y solicita el sitio.
La documentación de Azure contiene detalles adicionales sobre el uso de los servicios de Azure. Consulte los siguientes recursos:
Se recomienda usar una nueva ventana del explorador en privado o en incógnito para cada ejecución de prueba de la aplicación después de un cambio en la aplicación, la configuración de la aplicación o los servicios de Azure en Azure Portal. Los elementos cookie persistentes de una serie de pruebas anterior pueden dar errores de autenticación o autorización al probar el sitio, incluso aunque la configuración del sitio sea correcta. Para obtener más información sobre cómo configurar Visual Studio para abrir una nueva ventana de explorador en privado o incógnito para cada serie de pruebas, consulte la sección Cookies y datos del sitio.
Cuando se cambia la configuración de App Service en Azure Portal, las actualizaciones suelen surtir efecto rápidamente, pero no son instantáneas. A veces, debe esperar un breve período para que App Service se reinicie y se aplique un cambio de configuración.
Hospedaje en Azure App Service con firma de tokens de certificado
En las instrucciones de esta sección se explica lo siguiente:
- Cómo implementar una aplicación de Blazor WebAssembly hospedada con Identity Server para Azure App Service.
- Cómo crear y usar un certificado TLS para la firma de tokens Identity Server.
Nota
Para crear e implementar un certificado TLS para la comunicación del protocolo HTTPS después de seguir las instrucciones de esta sección, consulte la sección Uso de un dominio personalizado y un certificado TLS para la comunicación del protocolo HTTPS en Azure App Service de este artículo.
En la siguiente guía, se crea un certificado autofirmado en Azure Key Vault únicamente para la firma de tokens de Identity Server. La configuración de Identity Server usa el certificado del almacén de claves siguiendo diferentes enfoques para App Service de Windows y App Service de Linux:
- App Service de Windows: la aplicación accede al almacén de certificados de
CurrentUseryMypara cargar el certificado. - App Service de Linux: la aplicación carga el certificado manualmente.
Advertencia
Cuando busque usar un certificado para la firma de tokens Identity Server y dominio personalizado, no use el mismo certificado para la firma de tokens Identity Server y la comunicación segura HTTPS del sitio con exploradores:
- Usar certificados diferentes para estos dos requisitos es una buena práctica de seguridad porque aísla claves privadas para cada propósito.
- Los certificados TLS para la comunicación con los exploradores se administran de forma independiente sin afectar a la firma de tokens de Identity Server.
- Cuando Azure Key Vault proporciona un certificado a una aplicación de App Service para el enlace de dominio personalizado, Identity Server no puede obtener el mismo certificado de Azure Key Vault para la firma de tokens. Aunque es posible configurar Identity Server para que use el mismo certificado TLS desde una ruta de acceso física, la colocación de los certificados de seguridad en el control de código fuente es una práctica inadecuada y debe evitarse en la mayoría de los casos.
Para configurar una aplicación, Azure App Service y Azure Key Vault para que hospeden con un certificado de firma de tokens personalizado:
Cree un plan de App Service.
Nota
Se requiere un plan de App Service con un nivel de plan de
Basic B1o superior si también tiene previsto usar uno o varios dominios personalizados con la aplicación.Cree una nueva instancia de Azure Key Vault o use un almacén de claves existente en su suscripción de Azure.
En Azure Key Vault, genere un nuevo certificado autofirmado para la firma de tokens de Identity Server. Asigne al certificado un Nombre de certificado y un Firmante. El Firmante se especifica como
CN={COMMON NAME}, donde el marcador de posición{COMMON NAME}es el nombre común del certificado. El nombre común puede ser cualquier cadena alfanumérica. Por ejemplo,CN=IdentityServerSigninges un Firmante válido de certificado. Use la configuración predeterminada de la Configuración avanzada de directivas.Para crear el certificado, use uno de los métodos siguientes, o cualquier otra herramienta o servicio en línea adecuado:
Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.
Para más información sobre los certificados de Azure Key Vault, consulte Azure Key Vault: Certificados.
Vaya a Azure App Service en Azure Portal y cree un nuevo App Service con la siguiente configuración:
- Publicar establecido en
Code. - Pila en tiempo de ejecución establecido en el tiempo de ejecución de la aplicación.
- Para SKU y tamaño, confirme que el nivel de App Service sea
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.
- Publicar establecido en
Después de que Azure cree App Service, abra la Configuración de la aplicación y agregue una nueva configuración de aplicación que especifique la huella digital del certificado que se registró anteriormente. La clave de configuración de la aplicación es
WEBSITE_LOAD_CERTIFICATES:- Clave:
WEBSITE_LOAD_CERTIFICATES - Valor:
57443A552A46DB...D55E28D412B943565
En Azure Portal, guardar la configuración de la aplicación es un proceso de dos pasos: Guarde la configuración de clave-valor de
WEBSITE_LOAD_CERTIFICATESy, después, seleccione el botón Guardar, en la parte superior de la hoja.- Clave:
Seleccione la configuración de TLS/SSL de la aplicación. Seleccione Certificados de clave privada (.pfx) . Use el proceso Importar certificado de Key Vault para importar el certificado autofirmado del sitio para la firma de tokens de Identity Server.
Configure la aplicación para que use el certificado de firma de tokens según la elección del sistema operativo host, ya sea App Service de Windows o de Linux:
App Service de Windows
En Visual Studio, abra el archivo de configuración de la aplicación del proyecto Server (
appsettings.jsonoappsettings.Production.json). En la configuración de Identity Server, agregue la siguiente sección deKey. Especifique el Firmante del certificado autofirmado para la claveName. En el ejemplo siguiente, el nombre común del certificado asignado en el almacén de claves esIdentityServerSigning, lo que produce un Firmante deCN=IdentityServerSigning:"IdentityServer": { ... "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "CurrentUser", "Name": "CN=IdentityServerSigning" } },Si va a solucionar un problema de carga de certificados en App Service de Windows, ejecute el siguiente comando en un shell de comandos Kudu de PowerShell en Azure Portal. El comando proporciona una lista de certificados a los que la aplicación puede tener acceso desde el almacén de certificados de
CurrentUser>My. La salida incluye firmantes de certificados y huellas digitales útiles al depurar una aplicación:Get-ChildItem -path Cert:\CurrentUser\My -Recurse | Format-List DnsNameList, Subject, Thumbprint, EnhancedKeyUsageListApp Service de Linux
Linux no puede usar un almacén de certificados de Windows para cargar un certificado TLS. En App Service de Linux, los certificados se colocan en la ruta de acceso
/var/ssl/private/. Cargue y use manualmente el certificado de la ruta de acceso anterior.Si los siguientes espacios de nombres no están presentes en la parte superior de
Startup.csdel proyecto Server, agréguelos al archivo:using System; using System.IO; using System.Security.Cryptography.X509Certificates;En
Startup.ConfigureServices, actualice la configuración de Identity Server para que use un certificado cargado manualmente. En el ejemplo siguiente, el marcador de posición{THUMBPRINT}es la huella digital del certificado:var certPath = "/var/ssl/private/{THUMBPRINT}.p12"; if (File.Exists(certPath)) { var bytes = File.ReadAllBytes(certPath); var certificate = new X509Certificate2(bytes); services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => { }) .AddSigningCredential(certificate); } else { throw new FileNotFoundException($"Certificate path: {certPath}."); }En Visual Studio, cree un perfil de publicación de Azure App Service para el proyecto Server. En la barra de menús, seleccione: Compilar > Publicar > Nuevo > Azure > Azure App Service (Windows o Linux). Cuando Visual Studio se conecta a una suscripción de Azure, puede establecer la Vista de recursos de Azure por Tipo de recurso. Navegue dentro de la lista Aplicación web para buscar la instancia de App Service de la aplicación y selecciónela. Seleccione Finalizar.
Cuando Visual Studio vuelve a la ventana Publicar, se detectan automáticamente el almacén de claves y las dependencias del servicio de base de datos SQL Server.
No se requiere ningún cambio de configuración en la configuración predeterminada para el servicio del almacén de claves.
Con fines de prueba, la base de datos SQLite local de una aplicación, que está configurada de forma predeterminada por la plantilla de Blazor, puede implementarse con la aplicación sin configuración adicional. La configuración de una base de datos diferente en producción para Identity Server está fuera del ámbito de este artículo. Para obtener más información, consulte los recursos de base de datos en los siguientes recursos:
Publique la aplicación. Visual Studio abre una ventana del explorador y solicita el sitio.
La documentación de Azure contiene detalles adicionales sobre el uso de los servicios de Azure. Consulte los siguientes recursos:
Se recomienda usar una nueva ventana del explorador en privado o en incógnito para cada ejecución de prueba de la aplicación después de un cambio en la aplicación, la configuración de la aplicación o los servicios de Azure en Azure Portal. Los elementos cookie persistentes de una serie de pruebas anterior pueden dar errores de autenticación o autorización al probar el sitio, incluso aunque la configuración del sitio sea correcta. Para obtener más información sobre cómo configurar Visual Studio para abrir una nueva ventana de explorador en privado o incógnito para cada serie de pruebas, consulte la sección Cookies y datos del sitio.
Cuando se cambia la configuración de App Service en Azure Portal, las actualizaciones suelen surtir efecto rápidamente, pero no son instantáneas. A veces, debe esperar un breve período para que App Service se reinicie y se aplique un cambio de configuración.
Uso de un dominio personalizado y un certificado TLS para la comunicación del protocolo HTTPS en Azure App Service
En las instrucciones de esta sección se explica cómo crear y usar un certificado TLS para la comunicación del protocolo HTTPS con exploradores para una aplicación que se ha implementado en Azure App Service. Aunque la guía se centra en el uso del certificado con un dominio personalizado, se aplica igualmente al uso de un dominio predeterminado de aplicaciones de Azure, por ejemplo contoso.azurewebsites.net.
Nota
En las instrucciones de esta sección se da por supuesto que la aplicación ya está hospedada en Azure App Service. Si se implementa en App Service por primera vez, siga las instrucciones de la sección Escenarios de firma de tokens con Azure App Service antes de usar las instrucciones de esta sección.
Para configurar una aplicación, Azure App Service y Azure Key Vault para que hospeden con un dominio personalizado y HTTPS:
Use un plan de App Service con un nivel de plan
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.Cree un certificado PFX para la comunicación segura del explorador del sitio (protocolo HTTPS) con un nombre común del nombre de dominio completo (FQDN) del sitio que controla la organización (por ejemplo,
www.contoso.com). Cree el certificado con:- Usos de las claves
- Validación de firma digital (
digitalSignature) - Cifrado de claves (
keyEncipherment)
- Validación de firma digital (
- Usos mejorados/extendidos de las claves
- Autenticación de cliente (1.3.6.1.5.5.7.3.2)
- Autenticación del servidor (1.3.6.1.5.5.7.3.1)
Para crear el certificado, use uno de los métodos siguientes, o cualquier otra herramienta o servicio en línea adecuado:
Anote la contraseña, que se usará más adelante para importar el certificado en Azure Key Vault.
Para más información sobre los certificados de Azure Key Vault, consulte Azure Key Vault: Certificados.
- Usos de las claves
Cree una nueva instancia de Azure Key Vault o use un almacén de claves existente en su suscripción de Azure.
En el área Certificados del almacén de claves, importe el certificado del sitio PFX. Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.
En Azure Portal, en Azure App Service, para SKU y tamaño, confirme que el nivel de App Service sea
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.Abra la configuración de la aplicación en App Service y agregue una nueva configuración de la aplicación con una clave de
WEBSITE_LOAD_CERTIFICATES(si aún no existe) o modifique la configuración de la aplicaciónWEBSITE_LOAD_CERTIFICATESexistente. Especifique la huella digital del certificado TLS que registró anteriormente:- Cuando se usa la firma automática de tokens, solo hay una huella digital para la comunicación HTTPS. Clave de ejemplo:
WEBSITE_LOAD_CERTIFICATESValor de ejemplo:57443A552A46DB...D55E28D412B943565 - Cuando se usa un certificado de firma de token independiente, hay dos huellas digitales para la configuración con valores de huella digital separados por una coma. Clave de ejemplo:
WEBSITE_LOAD_CERTIFICATESValor de ejemplo:57443A552A46DB...D55E28D412B943565,29F43A772CB6AF...1D04F0C67F85FB0B1
En Azure Portal, guardar la configuración de la aplicación es un proceso de dos pasos: Guarde la configuración de clave-valor de
WEBSITE_LOAD_CERTIFICATESy, después, seleccione el botón Guardar, en la parte superior de la hoja.- Cuando se usa la firma automática de tokens, solo hay una huella digital para la comunicación HTTPS. Clave de ejemplo:
Seleccione la configuración de TLS/SSL de la aplicación. Seleccione Certificados de clave privada (.pfx) . Use el proceso Importar certificado de Key Vault para importar el certificado del sitio para la comunicación HTTPS.
Vaya a la hoja Dominios personalizados. En el sitio web del registrador de dominios, use la dirección IP y el id. de verificación del dominio personalizado para configurar el dominio. Una configuración de dominio típica incluye:
- Un registro A con un host de
@y un valor de la dirección IP de Azure Portal. - Un registro TXT con un host de
asuidy el valor del id. de verificación generado por Azure y proporcionado por Azure Portal.
Asegúrese de guardar correctamente los cambios en el sitio web del registrador de dominios. Algunos sitios web del registrador requieren un proceso de dos pasos para guardar los registros de dominio: Uno o varios registros se guardan individualmente seguidos de la actualización del registro del dominio con un botón independiente.
- Un registro A con un host de
Vuelva a la hoja Dominios personalizados en Azure Portal. Seleccione Agregar dominio personalizado. Seleccione la opción Registro A. Proporcione el dominio y seleccione Validar. Si los registros de dominio son correctos y están propagados por Internet, el portal le permitirá seleccionar el botón Agregar dominio personalizado.
Los cambios en el registro de dominio pueden tardar unos días en propagarse entre los servidores de nombres de dominio (DNS) de Internet después de que el registrador de dominios los procese. Si los registros de dominio no se actualizan en un plazo de tres días laborables, confirme que los registros se han establecido correctamente con el registrador de dominios y póngase en contacto con el servicio de soporte técnico al cliente.
En la hoja Dominios personalizados, el ESTADO SSL del dominio está marcado como
Not Secure. Seleccione el vínculo Agregar enlaces. Seleccione el certificado HTTPS del sitio en el almacén de claves para el enlace de dominio personalizado.
La documentación de Azure contiene detalles adicionales sobre el uso de servicios de Azure y de dominios personalizados con enlace de TLS en App Service, incluida información sobre el uso de registros CNAME en lugar de registros A. Para obtener más información, vea los siguientes recursos:
- Documentación de App Service
- Tutorial: Asignación de un nombre DNS personalizado existente a Azure App Service
- Protección de un nombre DNS personalizado con un enlace TLS/SSL en Azure App Service
- Azure Key Vault
Se recomienda usar una nueva ventana del explorador en privado o en incógnito para cada ejecución de prueba de la aplicación después de un cambio en la aplicación, la configuración de la aplicación o los servicios de Azure en Azure Portal. Los elementos cookie persistentes de una serie de pruebas anterior pueden dar errores de autenticación o autorización al probar el sitio, incluso aunque la configuración del sitio sea correcta. Para obtener más información sobre cómo configurar Visual Studio para abrir una nueva ventana de explorador en privado o incógnito para cada serie de pruebas, consulte la sección Cookies y datos del sitio.
Cuando se cambia la configuración de App Service en Azure Portal, las actualizaciones suelen surtir efecto rápidamente, pero no son instantáneas. A veces, debe esperar un breve período para que App Service se reinicie y se aplique un cambio de configuración.
Si va a solucionar un problema de carga de certificados en App Service de Windows, ejecute el siguiente comando en un shell de comandos Kudu de PowerShell en Azure Portal. El comando proporciona una lista de certificados a los que la aplicación puede tener acceso desde el almacén de certificados de CurrentUser > My. La salida incluye firmantes de certificados y huellas digitales útiles al depurar una aplicación:
Get-ChildItem -path Cert:\CurrentUser\My -Recurse | Format-List DnsNameList, Subject, Thumbprint, EnhancedKeyUsageList
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:
- Google Chrome (documentación de Google)
- Microsoft Edge
- Mozilla Firefox (documentación de Mozilla)
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:
- En Azure Portal, acceda al manifiesto de la aplicación.
- Establezca el atributo
allowPublicClientennullotrue.
- Error:
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
- Microsoft Edge:
- 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).
- Microsoft Edge: Use
- 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:
- Borre las memorias caché del paquete NuGet del sistema local ejecutando
dotnet nuget locals all --cleardesde un shell de comandos. - Elimine las carpetas
binyobjdel proyecto. - Restaure el proyecto y vuelva a compilarlo.
- 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
- Implementación en Azure App Service
- Importación de un certificado de Key Vault (documentación de Azure)
- Otros escenarios de seguridad de Blazor WebAssembly en ASP.NET Core
- Solicitudes de API web no autenticadas o no autorizadas en una aplicación con un cliente predeterminado seguro
- Configuración de ASP.NET Core para trabajar con servidores proxy y equilibradores de carga; incluye instrucciones relativas a lo siguiente:
- Uso de middleware de encabezados reenviados para retener la información de esquemas HTTPS en servidores proxy y redes internas.
- Escenarios y casos de uso adicionales, incluidos la configuración manual de esquemas, los cambios en las rutas de las solicitudes para corregir el enrutamiento de las solicitudes y el reenvío de esquemas de solicitudes para Linux y proxies inversos que no sean de tipo IIS.
En este artículo se explica cómo crear una solución Blazor WebAssembly hospedada que usa IdentityServer para autenticar usuarios y llamadas API.
Nota
Para configurar una aplicación Blazor WebAssembly independiente u hospedada para que use una instancia de Identity Server externa existente, siga las instrucciones de Protección de una aplicación independiente Blazor WebAssembly de ASP.NET Core con la biblioteca de autenticación.
Para crear un nuevo proyecto de Blazor WebAssembly con un mecanismo de autenticación:
Cree un nuevo proyecto.
Elija la plantilla Aplicación de Blazor WebAssembly . Seleccione Siguiente.
Proporcione un Nombre de proyecto sin usar guiones (vea la ADVERTENCIA siguiente). Confirme que la Ubicación es correcta. Seleccione Next (Siguiente).
Advertencia
Evite usar guiones (
-) en el nombre del proyecto 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).En el cuadro de diálogo Información adicional, seleccione Cuentas individuales como Tipo de autenticación para almacenar usuarios dentro de la aplicación mediante el sistema Identity de ASP.NET Core.
Active la casilla ASP.NET Core hospedado.
Configuración de la aplicación Server
En las siguientes secciones se describen algunas adiciones al proyecto cuando se incluye compatibilidad con la autenticación.
Clase Startup
La clase Startup tiene las siguientes adiciones.
En
Startup.ConfigureServices:ASP.NET Core Identity:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();IdentityServer con un método auxiliar AddApiAuthorization adicional que configura convenciones de ASP.NET Core predeterminadas por encima de IdentityServer:
services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();Autenticación con un método auxiliar AddIdentityServerJwt adicional que configura la aplicación para validar los tokens JWT generados por IdentityServer:
services.AddAuthentication() .AddIdentityServerJwt();
En
Startup.Configure:El middleware IdentityServer expone los puntos de conexión de OpenID Connect (OIDC):
app.UseIdentityServer();El middleware Authentication es responsable de validar las credenciales de solicitud y de configurar el usuario en el contexto de la solicitud:
app.UseAuthentication();El middleware Authorization habilita capacidades de autorización:
app.UseAuthorization();
Azure App Service en Linux
Al realizar una implementación en Azure App Service en Linux, especifique el emisor de forma explícita. Para obtener más información, vea Introducción a la autenticación de aplicaciones de página única en ASP.NET Core.
AddApiAuthorization
El método auxiliar AddApiAuthorization configura IdentityServer en escenarios de ASP.NET Core. IdentityServer es un marco eficaz y extensible que sirve para abordar los problemas de seguridad de las aplicaciones. IdentityServer expone las complejidades innecesarias en los escenarios más comunes. En consecuencia, se proporciona un conjunto de convenciones y opciones de configuración que consideramos un buen punto de partida. Cuando sus necesidades de autenticación cambien, tendrá a su disposición toda la eficacia de IdentityServer para personalizar la autenticación para adaptarse a los requisitos de una aplicación.
AddIdentityServerJwt
El método auxiliar AddIdentityServerJwt configura un esquema de directiva para la aplicación como el controlador de autenticación predeterminado. La directiva está configurada para permitir que Identity controle todas las solicitudes enrutadas a cualquier subruta en el espacio de dirección URL de Identity /Identity. JwtBearerHandler se encarga de todas las demás solicitudes. Este método también hace lo siguiente:
- Registra un recurso de API
{APPLICATION NAME}APIcon IdentityServer con un ámbito predeterminado de{APPLICATION NAME}API. - Configura el middleware de token de portador de JWT para validar los tokens emitidos por IdentityServer para la aplicación.
WeatherForecastController
En WeatherForecastController (Controllers/WeatherForecastController.cs), el atributo [Authorize] se aplica a la clase. Este atributo señala que, para acceder al recurso, el usuario debe estar autorizado en función de la directiva predeterminada. La directiva de autorización predeterminada está configurada para usar el esquema de autenticación predeterminado, que AddIdentityServerJwt configura. El método auxiliar configura JwtBearerHandler como el controlador predeterminado de las solicitudes a la aplicación.
ApplicationDbContext
En ApplicationDbContext (Data/ApplicationDbContext.cs), DbContext extiende ApiAuthorizationDbContext<TUser> para incluir el esquema de IdentityServer. La clase ApiAuthorizationDbContext<TUser> se deriva de la clase IdentityDbContext.
Para obtener el control total del esquema de la base de datos, herede de una de las clases DbContext de Identity disponibles y configure el contexto para incluir el esquema de Identity llamando a builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) en el método OnModelCreating.
OidcConfigurationController
En OidcConfigurationController (Controllers/OidcConfigurationController.cs), el punto de conexión del cliente se aprovisiona para proporcionar parámetros de OIDC.
Configuración de la aplicación
En el archivo de configuración de la aplicación (appsettings.json), en la raíz del proyecto, la sección IdentityServer describe la lista de clientes configurados. En el siguiente ejemplo hay un solo cliente, cuyo nombre corresponde al nombre de la aplicación y se asigna por convención al parámetro ClientId de OAuth. El perfil señala el tipo de aplicación que se está configurando. El perfil se usa internamente para controlar las convenciones que simplifican el proceso de configuración del servidor.
"IdentityServer": {
"Clients": {
"{APP ASSEMBLY}.Client": {
"Profile": "IdentityServerSPA"
}
}
}
El marcador de posición {APP ASSEMBLY} es el nombre de ensamblado de la aplicación (por ejemplo, BlazorSample.Client).
Configuración de la aplicación Client
Paquete de autenticación
Cuando una aplicación se crea para usar cuentas de usuario individuales (Individual), dicha aplicación recibe automáticamente una referencia de paquete del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication en el archivo de proyecto de la aplicación. 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.AspNetCore.Components.WebAssembly.Authentication"
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.
Configuración de HttpClient
En Program.cs, hay configurada una instancia de HttpClient ({APP ASSEMBLY}.ServerAPI) con nombre para proporcionar instancias de HttpClient que incluyen tokens de acceso al realizar solicitudes a la API de servidor:
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).
Nota
Si va a configurar una aplicación Blazor WebAssembly para usar una instancia de Identity Server existente que no forma parte de una solución hospedada por Blazor, cambie el registro de la dirección base HttpClient de IWebAssemblyHostEnvironment.BaseAddress (builder.HostEnvironment.BaseAddress) a la dirección URL del punto de conexión de autorización de API de la aplicación de servidor.
Compatibilidad con autorización de API
La compatibilidad para autenticar usuarios se incluye en el contenedor de servicios con el método de extensión proporcionado dentro del paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication. Este método configura los servicios necesarios para que la aplicación interactúe con el sistema de autorización existente.
builder.Services.AddApiAuthorization();
La configuración de la aplicación se carga por convención de forma predeterminada desde _configuration/{client-id}. Por convención, el identificador de cliente se establece en el nombre de ensamblado de la aplicación. Esta dirección URL se puede cambiar para que apunte a un punto de conexión aparte llamando a la sobrecarga con opciones.
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.AspNetCore.Components.WebAssembly.Authentication/
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
RedirectToLoginadministra 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
maindel 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 ramarelease/5.0para 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 vínculo a la página de perfil de usuario en ASP.NET Core Identity.
- Proporciona un botón para cerrar la sesión de la aplicación.
- En el caso de los usuarios anónimos:
- Ofrece la opción de registrarse.
- Ofrece la opción de iniciar sesión.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
<a href="authentication/profile">Hello, @context.User.Identity.Name!</a>
<button class="nav-link btn btn-link" @onclick="BeginSignOut">
Log out
</button>
</Authorized>
<NotAuthorized>
<a href="authentication/register">Register</a>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code {
private async Task BeginSignOut(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:
- Se proporciona mediante el paquete
Microsoft.AspNetCore.Components.WebAssembly.Authentication. - Administra la realización de las acciones adecuadas en cada fase de autenticación.
@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.
Notificaciones name y role con autorización de API
Fábrica de usuario personalizada
En la aplicación Client , cree una fábrica de usuario personalizada. Identity Server envía varios roles como una matriz JSON en una sola notificación role. Se envía un único rol como un valor de cadena en la notificación. La fábrica crea una notificación role individual por cada uno de los roles del usuario.
CustomUserFactory.cs:
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomUserFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
En la aplicación Client , registre la fábrica en Program.cs:
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<CustomUserFactory>();
En la aplicación Server , llame a AddRoles en el generador de Identity, que agrega servicios relativos a roles:
using Microsoft.AspNetCore.Identity;
...
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Configuración de Identity Server
Siga uno de estos procedimientos:
Opciones de autorización de API
En la aplicación Server :
- Configure Identity Server para colocar las notificaciones
nameyroleen el token de identificador y el token de acceso. - Evite la asignación predeterminada de roles en el controlador de token JWT.
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
...
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Servicio de perfil
En la aplicación Server , cree una implementación ProfileService.
ProfileService.cs:
using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Services;
using System.Threading.Tasks;
public class ProfileService : IProfileService
{
public ProfileService()
{
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
context.IssuedClaims.AddRange(nameClaim);
var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
context.IssuedClaims.AddRange(roleClaims);
await Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
await Task.CompletedTask;
}
}
En la aplicación Server , registre el servicio de perfil en Startup.ConfigureServices:
using IdentityServer4.Services;
...
services.AddTransient<IProfileService, ProfileService>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Uso de mecanismos de autorización
En la aplicación Client , los métodos de autorización de componentes son funcionales en este momento. Cualquiera de los mecanismos de autorización de los componentes puede usar un rol para autorizar al usuario:
Componente
AuthorizeView(ejemplo:<AuthorizeView Roles="admin">)Directiva de atributo
[Authorize](AuthorizeAttribute) (ejemplo:@attribute [Authorize(Roles = "admin")])Lógica de procedimientos (ejemplo:
if (user.IsInRole("admin")) { ... })Se admiten pruebas de rol múltiple:
if (user.IsInRole("admin") && user.IsInRole("developer")) { ... }
User.Identity.Name se rellena en la aplicación Client con el nombre de usuario del usuario, que suele ser su dirección de correo electrónico de inicio de sesión.
UserManager y SignInManager
Establezca el tipo de notificaciones de identificador de usuario cuando una aplicación de servidor requiera:
- UserManager<TUser> o SignInManager<TUser> en un punto de conexión de API.
- Detalles de IdentityUser, como el nombre de usuario, la dirección de correo electrónico o la hora de finalización del bloqueo.
En Startup.ConfigureServices:
using System.Security.Claims;
...
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
El elemento WeatherForecastController siguiente registra la propiedad UserName cuando se llama al método Get:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using {APP NAMESPACE}.Server.Models;
using {APP NAMESPACE}.Shared;
namespace {APP NAMESPACE}.Server.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly UserManager<ApplicationUser> userManager;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm",
"Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger,
UserManager<ApplicationUser> userManager)
{
this.logger = logger;
this.userManager = userManager;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
var rng = new Random();
var user = await userManager.GetUserAsync(User);
if (user != null)
{
logger.LogInformation($"User.Identity.Name: {user.UserName}");
}
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Host en Azure App Service con un dominio personalizado y un certificado
En la guía siguiente se explica:
- Cómo implementar una aplicación de Blazor WebAssembly hospedada con Identity Server para Azure App Service con un dominio personalizado.
- Cómo crear y usar un certificado TLS para la comunicación del protocolo HTTPS con exploradores. Aunque la guía se centra en el uso del certificado con un dominio personalizado, la guía se aplica igualmente al uso de un dominio predeterminado de aplicaciones de Azure, por ejemplo
contoso.azurewebsites.net.
En este escenario de hospedaje, no use el mismo certificado para la clave de firma de tokens de Identity Server y la comunicación segura HTTPS del sitio con exploradores:
- Usar certificados diferentes para estos dos requisitos es una buena práctica de seguridad porque aísla claves privadas para cada propósito.
- Los certificados TLS para la comunicación con los exploradores se administran de forma independiente sin afectar a la firma de tokens de Identity Server.
- Cuando Azure Key Vault proporciona un certificado a una aplicación de App Service para el enlace de dominio personalizado, Identity Server no puede obtener el mismo certificado de Azure Key Vault para la firma de tokens. Aunque es posible configurar Identity Server para que use el mismo certificado TLS desde una ruta de acceso física, la colocación de los certificados de seguridad en el control de código fuente es una práctica inadecuada y debe evitarse en la mayoría de los casos.
En la siguiente guía, se crea un certificado autofirmado en Azure Key Vault únicamente para la firma de tokens de Identity Server. La configuración de Identity Server usa el certificado del almacén de claves mediante el almacén de certificados CurrentUser > My de la aplicación. Otros certificados que se usan para el tráfico HTTPS con dominios personalizados se crean y se configuran de forma independiente del certificado de firma de Identity Server.
Para configurar una aplicación, Azure App Service y Azure Key Vault para que hospeden con un dominio personalizado y HTTPS:
Cree un plan de App Service con un nivel de plan de
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.Cree un certificado PFX para la comunicación segura del explorador del sitio (protocolo HTTPS) con un nombre común del nombre de dominio completo (FQDN) del sitio que controla la organización (por ejemplo,
www.contoso.com). Cree el certificado con:- Usos de las claves
- Validación de firma digital (
digitalSignature) - Cifrado de claves (
keyEncipherment)
- Validación de firma digital (
- Usos mejorados/extendidos de las claves
- Autenticación de cliente (1.3.6.1.5.5.7.3.2)
- Autenticación del servidor (1.3.6.1.5.5.7.3.1)
Para crear el certificado, use uno de los métodos siguientes, o cualquier otra herramienta o servicio en línea adecuado:
Anote la contraseña, que se usará más adelante para importar el certificado en Azure Key Vault.
Para más información sobre los certificados de Azure Key Vault, consulte Azure Key Vault: Certificados.
- Usos de las claves
Cree una nueva instancia de Azure Key Vault o use un almacén de claves existente en su suscripción de Azure.
En el área Certificados del almacén de claves, importe el certificado del sitio PFX. Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.
En Azure Key Vault, genere un nuevo certificado autofirmado para la firma de tokens de Identity Server. Asigne al certificado un Nombre de certificado y un Firmante. El Firmante se especifica como
CN={COMMON NAME}, donde el marcador de posición{COMMON NAME}es el nombre común del certificado. El nombre común puede ser cualquier cadena alfanumérica. Por ejemplo,CN=IdentityServerSigninges un Firmante válido de certificado. Use la configuración predeterminada de la Configuración avanzada de directivas. Registre la huella digital del certificado, que se usará en la configuración de la aplicación más adelante.Vaya a Azure App Service en Azure Portal y cree un nuevo App Service con la siguiente configuración:
- Publicar establecido en
Code. - Pila en tiempo de ejecución establecido en el tiempo de ejecución de la aplicación.
- Para SKU y tamaño, confirme que el nivel de App Service sea
Basic B1o superior. App Service requiere un nivel de servicioBasic B1o superior para usar dominios personalizados.
- Publicar establecido en
Después de que Azure cree App Service, abra la Configuración de la aplicación y agregue una nueva configuración de aplicación que especifique las huellas digitales del certificado que se registraron anteriormente. La clave de configuración de la aplicación es
WEBSITE_LOAD_CERTIFICATES. Separe las huellas digitales de certificado en el valor de configuración de la aplicación con una coma, como se muestra en el ejemplo siguiente:- Clave:
WEBSITE_LOAD_CERTIFICATES - Valor:
57443A552A46DB...D55E28D412B943565,29F43A772CB6AF...1D04F0C67F85FB0B1
En Azure Portal, guardar la configuración de la aplicación es un proceso de dos pasos: Guarde la configuración de clave-valor de
WEBSITE_LOAD_CERTIFICATESy, después, seleccione el botón Guardar, en la parte superior de la hoja.- Clave:
Seleccione la configuración de TLS/SSL de la aplicación. Seleccione Certificados de clave privada (.pfx) . Use el proceso Importar certificado de Key Vault dos veces para importar el certificado del sitio para la comunicación HTTPS y el certificado autofirmado del sitio para la firma de tokens de Identity Server.
Vaya a la hoja Dominios personalizados. En el sitio web del registrador de dominios, use la dirección IP y el id. de verificación del dominio personalizado para configurar el dominio. Una configuración de dominio típica incluye:
- Un registro A con un host de
@y un valor de la dirección IP de Azure Portal. - Un registro TXT con un host de
asuidy el valor del id. de verificación generado por Azure y proporcionado por Azure Portal.
Asegúrese de guardar correctamente los cambios en el sitio web del registrador de dominios. Algunos sitios web del registrador requieren un proceso de dos pasos para guardar los registros de dominio: Uno o varios registros se guardan individualmente seguidos de la actualización del registro del dominio con un botón independiente.
- Un registro A con un host de
Vuelva a la hoja Dominios personalizados en Azure Portal. Seleccione Agregar dominio personalizado. Seleccione la opción Registro A. Proporcione el dominio y seleccione Validar. Si los registros de dominio son correctos y están propagados por Internet, el portal le permitirá seleccionar el botón Agregar dominio personalizado.
Los cambios en el registro de dominio pueden tardar unos días en propagarse entre los servidores de nombres de dominio (DNS) de Internet después de que el registrador de dominios los procese. Si los registros de dominio no se actualizan en un plazo de tres días laborables, confirme que los registros se han establecido correctamente con el registrador de dominios y póngase en contacto con el servicio de soporte técnico al cliente.
En la hoja Dominios personalizados, el ESTADO SSL del dominio está marcado como
Not Secure. Seleccione el vínculo Agregar enlaces. Seleccione el certificado HTTPS del sitio en el almacén de claves para el enlace de dominio personalizado.En Visual Studio, abra el archivo de configuración de la aplicación del proyecto Server (
appsettings.jsonoappsettings.Production.json). En la configuración de Identity Server, agregue la siguiente sección deKey. Especifique el Firmante del certificado autofirmado para la claveName. En el ejemplo siguiente, el nombre común del certificado asignado en el almacén de claves esIdentityServerSigning, lo que produce un Firmante deCN=IdentityServerSigning:"IdentityServer": { ... "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "CurrentUser", "Name": "CN=IdentityServerSigning" } },En Visual Studio, cree un perfil de publicación de Azure App Service para el proyecto Server. En la barra de menús, seleccione: Compilar > Publicar > Nuevo > Azure > Azure App Service (Windows o Linux). Cuando Visual Studio se conecta a una suscripción de Azure, puede establecer la Vista de recursos de Azure por Tipo de recurso. Navegue dentro de la lista Aplicación web para buscar la instancia de App Service de la aplicación y selecciónela. Seleccione Finalizar.
Cuando Visual Studio vuelve a la ventana Publicar, se detectan automáticamente el almacén de claves y las dependencias del servicio de base de datos SQL Server.
No se requiere ningún cambio de configuración en la configuración predeterminada para el servicio del almacén de claves.
Con fines de prueba, la base de datos SQLite local de una aplicación, que está configurada de forma predeterminada por la plantilla de Blazor, puede implementarse con la aplicación sin configuración adicional. La configuración de una base de datos diferente en producción para Identity Server está fuera del ámbito de este artículo. Para obtener más información, consulte los recursos de base de datos en los siguientes recursos:
Seleccione el enlace Editar debajo del nombre del perfil de implementación en la parte superior de la ventana. Cambie la dirección URL de destino a la dirección URL de dominio personalizada del sitio (por ejemplo,
https://www.contoso.com). Guarde la configuraciónPublique la aplicación. Visual Studio abre una ventana del explorador y solicita el sitio en su dominio personalizado.
La documentación de Azure contiene detalles adicionales sobre el uso de servicios de Azure y de dominios personalizados con enlace de TLS en App Service, incluida información sobre el uso de registros CNAME en lugar de registros A. Para obtener más información, vea los siguientes recursos:
- Documentación de App Service
- Tutorial: Asignación de un nombre DNS personalizado existente a Azure App Service
- Protección de un nombre DNS personalizado con un enlace TLS/SSL en Azure App Service
- Azure Key Vault
Se recomienda usar una nueva ventana del explorador en privado o en incógnito para cada ejecución de prueba de la aplicación después de un cambio en la aplicación, la configuración de la aplicación o los servicios de Azure en Azure Portal. Los elementos cookie persistentes de una serie de pruebas anterior pueden dar errores de autenticación o autorización al probar el sitio, incluso aunque la configuración del sitio sea correcta. Para obtener más información sobre cómo configurar Visual Studio para abrir una nueva ventana de explorador en privado o incógnito para cada serie de pruebas, consulte la sección Cookies y datos del sitio.
Cuando se cambia la configuración de App Service en Azure Portal, las actualizaciones suelen surtir efecto rápidamente, pero no son instantáneas. A veces, debe esperar un breve período para que App Service se reinicie y se aplique un cambio de configuración.
Si va a solucionar un problema de carga de certificados, ejecute el siguiente comando en un shell de comandos Kudu de PowerShell en Azure Portal. El comando proporciona una lista de certificados a los que la aplicación puede tener acceso desde el almacén de certificados de CurrentUser > My. La salida incluye firmantes de certificados y huellas digitales útiles al depurar una aplicación:
Get-ChildItem -path Cert:\CurrentUser\My -Recurse | Format-List DnsNameList, Subject, Thumbprint, EnhancedKeyUsageList
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:
- Google Chrome (documentación de Google)
- Microsoft Edge
- Mozilla Firefox (documentación de Mozilla)
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:
- En Azure Portal, acceda al manifiesto de la aplicación.
- Establezca el atributo
allowPublicClientennullotrue.
- Error:
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
- Microsoft Edge:
- 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).
- Microsoft Edge: Use
- 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:
- Borre las memorias caché del paquete NuGet del sistema local ejecutando
dotnet nuget locals all --cleardesde un shell de comandos. - Elimine las carpetas
binyobjdel proyecto. - Restaure el proyecto y vuelva a compilarlo.
- 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
- Implementación en Azure App Service
- Importación de un certificado de Key Vault (documentación de Azure)
- Otros escenarios de seguridad de Blazor WebAssembly en ASP.NET Core
- Solicitudes de API web no autenticadas o no autorizadas en una aplicación con un cliente predeterminado seguro
- Configuración de ASP.NET Core para trabajar con servidores proxy y equilibradores de carga; incluye instrucciones relativas a lo siguiente:
- Uso de middleware de encabezados reenviados para retener la información de esquemas HTTPS en servidores proxy y redes internas.
- Escenarios y casos de uso adicionales, incluidos la configuración manual de esquemas, los cambios en las rutas de las solicitudes para corregir el enrutamiento de las solicitudes y el reenvío de esquemas de solicitudes para Linux y proxies inversos que no sean de tipo IIS.