Autenticación y autorización de ASP.NET Core Blazor
En este artículo se describe la compatibilidad de ASP.NET Core con la configuración y administración de la seguridad en aplicaciones Blazor.
Los escenarios de seguridad difieren entre las aplicaciones de Blazor Server y Blazor WebAssembly. Debido a que las aplicaciones de Blazor Server se ejecutan en el servidor, las comprobaciones de autorización pueden determinar:
- Las opciones de la interfaz de usuario presentadas a un usuario (por ejemplo, qué entradas de menú están disponibles para el usuario).
- Las reglas de acceso para las áreas de la aplicación y los componentes.
Las aplicaciones de Blazor WebAssembly se ejecutan en el cliente. La autorización solo se utiliza para determinar qué opciones de la interfaz de usuario se van a mostrar. Dado que el usuario puede modificar u omitir las comprobaciones en el cliente, las aplicaciones de Blazor WebAssembly no pueden aplicar reglas de acceso de autorización.
Las convenciones de autorización de Razor Pages no se aplican a los componentes de Razor enrutables. Si se inserta un componente no enrutable de Razor en una página, las convenciones de autorización de esta afectan indirectamente al componente de Razor y al resto del contenido de la página.
Nota:
Las aplicaciones de ASP.NET Core que usan Identity de ASP.NET Core para la administración de usuarios deben utilizar Razor Pages en lugar de componentes Razor para la interfaz de usuario relacionada con la identidad, como el registro de usuarios, el inicio de sesión, el cierre de sesión y otras tareas de administración de usuarios. Identity de ASP.NET Core se ha diseñado para funcionar en un contexto de solicitud y respuesta HTTP, lo cual no está disponible con carácter general en las aplicaciones de Blazor. Las abstracciones de ASP.NET Core, como SignInManager<TUser> y UserManager<TUser>, no se admiten en los componentes Razor. Para obtener más información sobre el uso de Identity de ASP.NET Core con Blazor, consulte el documento para agregar scaffolding Identity de ASP.NET Core en una aplicación de Blazor Server.
Autenticación
Blazor usa los mecanismos de autenticación de ASP.NET Core existentes para establecer la identidad del usuario. El mecanismo exacto depende de la forma en la que se hospeda la aplicación de Blazor: Blazor WebAssembly o Blazor Server.
autenticación Blazor WebAssembly
En las aplicaciones de Blazor WebAssembly, las comprobaciones de autenticación pueden omitirse porque los usuarios pueden modificar todos los códigos del lado cliente. Lo mismo se aplica a todas las tecnologías de aplicaciones del lado cliente, incluidas las plataformas JavaScript SPA o las aplicaciones nativas para cualquier sistema operativo.
Agregue la siguiente línea de código:
Agregue una referencia de paquete para
Microsoft.AspNetCore.Components.Authorization.Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (NuGet documentación). Confirme las versiones correctas del paquete en NuGet.org.
El espacio de nombres de
Microsoft.AspNetCore.Components.Authorizational archivo_Imports.razorde la aplicación.
Para controlar la autenticación, el uso de un servicio AuthenticationStateProvider integrado o personalizado se describe en las secciones siguientes.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de ASP.NET Core Blazor WebAssembly.
autenticación Blazor Server
Las aplicaciones de Blazor Server funcionan mediante una conexión en tiempo real que se crea con SignalR. La autenticación en aplicaciones basadas en SignalR se controla cuando se establece la conexión. La autenticación se puede basar en una cookie o en cualquier otro token de portador.
El servicio AuthenticationStateProvider integrado para aplicaciones Blazor Server obtiene datos de estado de autenticación de HttpContext.User de ASP.NET Core. Así es como el estado de autenticación se integra con los mecanismos de autenticación de ASP.NET Core.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de aplicaciones de ASP.NET Core Blazor Server.
Servicio AuthenticationStateProvider
AuthenticationStateProvider es el servicio subyacente utilizado por el componente AuthorizeView y el componente CascadingAuthenticationState para obtener el estado de autenticación.
Por lo general, no se utiliza AuthenticationStateProvider directamente. Use los enfoques del componente AuthorizeView o Task<AuthenticationState> descritos más adelante en este artículo. El principal inconveniente de utilizar AuthenticationStateProvider directamente es que el componente no se notifica de manera automática si cambia el estado de autenticación subyacente de los datos.
El servicio AuthenticationStateProvider puede proporcionar los datos ClaimsPrincipal del usuario actual, como se muestra en el ejemplo siguiente:
@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
<h3>ClaimsPrincipal Data</h3>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Count() > 0)
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surnameMessage</p>
@code {
private string authMessage;
private string surnameMessage;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surnameMessage =
$"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true y porque el usuario es ClaimsPrincipal, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Para más información sobre la inserción de dependencias (DI) y servicios, consulte Inserción de dependencias de Blazor de ASP.NET Core y Inserción de dependencias en ASP.NET Core. Para obtener información sobre cómo implementar una instancia de AuthenticationStateProvider personalizada en las aplicaciones de Blazor Server, consulte Protección de aplicaciones Blazor Server de ASP.NET Core.
Exposición del estado de autenticación como un parámetro en cascada
Si se requieren los datos de estado de autenticación para la lógica de procedimiento, como cuando se realiza una acción desencadenada por el usuario, obtenga los datos de estado de autenticación mediante la definición de un parámetro en cascada del tipo Task<AuthenticationState>:
@page "/"
<button @onclick="LogUsername">Log username</button>
<p>@authMessage</p>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private string authMessage;
private async Task LogUsername()
{
var authState = await authenticationStateTask;
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Configure el parámetro en cascada Task<AuthenticationState> mediante los componentes AuthorizeRouteView y CascadingAuthenticationState en el componente App (App.razor):
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
En una aplicación de Blazor WebAssembly, agregue servicios relativos a opciones y autorización a Program.cs:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
En una aplicación de Blazor Server, ya existen servicios para opciones y autorización, por lo que no es necesario realizar ninguna otra acción.
Autorización
Cuando un usuario está autenticado, se aplican las reglas de autorización para controlar qué puede hacer el usuario.
Por lo general, se concede o deniega el acceso en función de si:
- El usuario está autenticado (ha iniciado sesión).
- El usuario está en un rol.
- El usuario tiene una notificación.
- Una directiva se cumple.
Cada uno de estos conceptos tiene su equivalente en una aplicación ASP.NET Core MVC o Razor Pages. Para más información sobre la seguridad de ASP.NET Core, consulte los artículos disponibles en Seguridad e Identity de ASP.NET Core.
Componente AuthorizeView
El componente AuthorizeView selectivamente muestra el contenido de la interfaz de usuario dependiendo de si el usuario tiene la autorización necesaria. Este enfoque es útil cuando solo necesite mostrar datos del usuario y no es necesario usar la identidad del usuario en la lógica de procedimientos.
El componente expone una variable context del tipo AuthenticationState, que puede utilizar para acceder a la información sobre el usuario que ha iniciado sesión:
<AuthorizeView>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</AuthorizeView>
También puede proporcionar contenido diferente para mostrar si el usuario no está autorizado:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authorized.</p>
<button @onclick="SecureMethod">Authorized Only Button</button>
</Authorized>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private void SecureMethod() { ... }
}
El contenido de las etiquetas <Authorized> y <NotAuthorized> puede incluir elementos arbitrarios, como otros componentes interactivos.
Solo los usuarios autorizados pueden invocar los controladores de eventos predeterminados de un elemento autorizado, como el método SecureMethod del elemento <button> que hay en el ejemplo anterior.
Las condiciones de autorización, como los roles o directivas que controlan las opciones o el acceso a la interfaz de usuario, se tratan en la sección Autorización.
Si no se especifican las condiciones de la autorización, AuthorizeView usa una directiva predeterminada y trata:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
El componente AuthorizeView se puede usar en el componente NavMenu (Shared/NavMenu.razor) para mostrar un componente NavLink (NavLink), pero tenga en cuenta que este enfoque solo quita el elemento de lista de la salida representada. No impide que el usuario navegue hasta el componente.
Las aplicaciones creadas a partir de una plantilla de proyecto de Blazor que incluyen autenticación utilizan un componente LoginDisplay que depende de un componente AuthorizeView. El componente AuthorizeView muestra selectivamente el contenido a los usuarios para el trabajo relacionado con Identity. El ejemplo siguiente procede de la plantilla de proyecto de Blazor WebAssembly.
Shared/LoginDisplay.razor:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code{
private async Task BeginLogout(MouseEventArgs args)
{
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
El ejemplo siguiente procede de la plantilla de proyecto de Blazor Server y utiliza puntos de conexión de Identity de ASP.NET Core en el área Identity de la aplicación para procesar el trabajo relacionado con Identity.
Shared/LoginDisplay.razor:
<AuthorizeView>
<Authorized>
<a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
<form method="post" action="Identity/Account/LogOut">
<button type="submit" class="nav-link btn btn-link">Log out</button>
</form>
</Authorized>
<NotAuthorized>
<a href="Identity/Account/Register">Register</a>
<a href="Identity/Account/Login">Log in</a>
</NotAuthorized>
</AuthorizeView>
Autorización basada en roles y en directivas
El componente AuthorizeView admite la autorización basada en roles o basada en directivas.
Para la autorización basada en roles, utilice el parámetro Roles:
<AuthorizeView Roles="admin, superuser">
<p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>
Para más información, además de una guía de configuración, consulte Autorización basada en roles en ASP.NET Core.
Para la autorización basada en directivas, utilice el parámetro Policy:
<AuthorizeView Policy="content-editor">
<p>You can only see this if you satisfy the "content-editor" policy.</p>
</AuthorizeView>
La autorización basada en notificaciones es un caso especial de autorización basada en directivas. Por ejemplo, puede definir una directiva que requiere que los usuarios tengan una notificación determinada. Para obtener más información, vea Autorización basada en directivas en ASP.NET Core.
Estas API se pueden usar en aplicaciones de Blazor Server o Blazor WebAssembly.
Si no se especifica Roles ni Policy, AuthorizeView usa la directiva predeterminada.
Contenido que se muestra durante la autenticación asincrónica
Blazor permite que el estado de autenticación se determine asincrónicamente. El escenario principal de este enfoque se encuentra en las aplicaciones de Blazor WebAssembly que realizan una solicitud de autenticación a un punto de conexión externo.
Mientras la autenticación está en curso, AuthorizeView no muestra ningún contenido de forma predeterminada. Para mostrar el contenido mientras se produce autenticación, use la etiqueta <Authorizing>:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</Authorized>
<Authorizing>
<h1>Authentication in progress</h1>
<p>You can only see this content while authentication is in progress.</p>
</Authorizing>
</AuthorizeView>
Este enfoque no se aplica normalmente a las aplicaciones de Blazor Server. Las aplicaciones de Blazor Server conocen el estado de autenticación tan pronto como se establece dicho estado. El contenido Authorizing puede proporcionarse en un componente AuthorizeView de una aplicación de Blazor Server, pero nunca se muestra.
Atributo [Authorize]
El atributo [Authorize] se puede usar en los componentes de Razor:
@page "/"
@attribute [Authorize]
You can only see this if you're signed in.
Importante
Utilice únicamente [Authorize] en componentes @page a los que se llega a través del enrutador de Blazor. La autorización solo se realiza como un aspecto del enrutamiento y no para los componentes secundarios representados dentro de una página. Para autorizar la presentación de partes concretas dentro de una página, use AuthorizeView en su lugar.
El atributo [Authorize] admite también la autorización basada en roles o basada en directivas. Para la autorización basada en roles, utilice el parámetro Roles:
@page "/"
@attribute [Authorize(Roles = "admin, superuser")]
<p>You can only see this if you're in the 'admin' or 'superuser' role.</p>
Para la autorización basada en directivas, utilice el parámetro Policy:
@page "/"
@attribute [Authorize(Policy = "content-editor")]
<p>You can only see this if you satisfy the 'content-editor' policy.</p>
Si no se especifica Roles ni Policy, [Authorize] usa la directiva predeterminada, que consiste en tratar:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
Autorización de recursos
Para autorizar a los usuarios para los recursos, pase los datos de ruta de la solicitud al parámetro Resource de AuthorizeRouteView.
En el contenido de Router.Found de una ruta solicitada en el componente App (App.razor):
<AuthorizeRouteView Resource="@routeData" RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
Para obtener más información sobre cómo se pasan los datos de estado de autorización y cómo se usan en la lógica de procedimientos, consulte la sección Exposición del estado de autenticación como parámetro en cascada.
Cuando la AuthorizeRouteView recibe los datos de ruta del recurso, las directivas de autorización tienen acceso RouteData.PageType a y RouteData.RouteValues que permiten que la lógica personalizada tome decisiones de autorización.
En el ejemplo siguiente, se crea una directiva EditUser en AuthorizationOptions para la configuración del servicio de autorización de la aplicación (AddAuthorizationCore) con la lógica siguiente:
- Determine si existe un valor de ruta con una clave de
id. Si la clave existe, el valor de ruta se almacena envalue. - En una variable denominada
id, almacenevaluecomo una cadena o establezca un valor de cadena vacío (string.Empty). - Si
idno es una cadena vacía, aserte que la directiva se cumple (devuelvetrue) si el valor de la cadena comienza porEMP. De lo contrario, aserte que se produce un error en la directiva (devuelvefalse).
En Program.cs o Startup.cs (según el modelo de hospedaje y la versión del marco):
Agregue espacios de nombres de Microsoft.AspNetCore.Components y System.Linq:
using Microsoft.AspNetCore.Components; using System.Linq;Agregue la directiva:
options.AddPolicy("EditUser", policy => policy.RequireAssertion(context => { if (context.Resource is RouteData rd) { var routeValue = rd.RouteValues.TryGetValue("id", out var value); var id = Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty; if (!string.IsNullOrEmpty(id)) { return id.StartsWith("EMP", StringComparison.InvariantCulture); } } return false; }) );
El ejemplo anterior es una directiva de autorización sobreimplificada, que simplemente se usa para demostrar el concepto con un ejemplo práctico. Para obtener más información sobre la creación y configuración de directivas de autorización, vea Autorización basada en directivas en ASP.NET Core.
En el componente EditUser siguiente, el recurso en /users/{id}/edit tiene un parámetro de ruta para el identificador del usuario ({id}). El componente usa la directiva de autorización EditUser anterior para determinar si el valor de ruta de id comienza por EMP. Si id comienza por EMP, la directiva se aplica correctamente y se autoriza el acceso al componente. Si id comienza con un valor distinto de EMP o si id es una cadena vacía, se produce un error en la directiva y el componente no se carga.
Pages/EditUser.razor:
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The 'EditUser' policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string Id { get; set; }
}
Personalización del contenido no autorizado con el componente de enrutador
El componente Router, junto con el componente AuthorizeRouteView, permite que la aplicación especifique el contenido personalizado si:
- El usuario produce un error en la condición
[Authorize]aplicada al componente. Se muestra el marcado del elemento<NotAuthorized>. El atributo[Authorize]se describe en la sección Atributo[Authorize]. - La autorización asincrónica está en curso, lo que normalmente significa que el proceso de autenticación del usuario está en curso. Se muestra el marcado del elemento
<Authorizing>. - No se encuentra el contenido. Se muestra el marcado del elemento
<NotFound>.
En la plantilla de proyecto de Blazor Server predeterminada, el componente App (App.razor) muestra cómo configurar el contenido personalizado:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
<h1>Sorry</h1>
<p>You're not authorized to reach this page.</p>
<p>You may need to log in as a different user.</p>
</NotAuthorized>
<Authorizing>
<h1>Authorization in progress</h1>
<p>Only visible while authorization is in progress.</p>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
El contenido de las etiquetas <NotFound>, <NotAuthorized> y <Authorizing> puede incluir elementos arbitrarios, como otros componentes interactivos.
Si no se especifica la etiqueta <NotAuthorized>, AuthorizeRouteView usa el siguiente mensaje de reserva:
Not authorized.
Lógica de procedimientos
Si se requiere que la aplicación compruebe las reglas de autorización como parte de la lógica de procedimiento, utilice un parámetro en cascada del tipo Task<AuthenticationState> para obtener el ClaimsPrincipal del usuario. Task<AuthenticationState> se puede combinar con otros servicios, como IAuthorizationService, para evaluar las directivas.
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private async Task DoSomething()
{
var user = (await authenticationStateTask).User;
if (user.Identity.IsAuthenticated)
{
// Perform an action only available to authenticated (signed-in) users.
}
if (user.IsInRole("admin"))
{
// Perform an action only available to users in the 'admin' role.
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// Perform an action only available to users satisfying the
// 'content-editor' policy.
}
}
}
Nota:
En un componente de la aplicación de Blazor WebAssembly, agregue los espacios de nombres Microsoft.AspNetCore.Authorization y Microsoft.AspNetCore.Components.Authorization:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
Estos espacios de nombres se pueden proporcionar globalmente si se agregan al archivo _Imports.razor de la aplicación.
Solucionar problemas
Errores comunes:
La autorización requiere un parámetro en cascada de tipo
Task<AuthenticationState>. Considere la posibilidad de usarCascadingAuthenticationStatepara proporcionarlo.Se recibe el valor
nullparaauthenticationStateTask
Es probable que el proyecto no se haya creado mediante una plantilla de Blazor Server con la autenticación habilitada. Encapsule un <CascadingAuthenticationState> alrededor de alguna parte del árbol de la interfaz de usuario, por ejemplo, en el componente App (App.razor) de la siguiente manera:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
...
</Router>
</CascadingAuthenticationState>
El CascadingAuthenticationState proporciona el parámetro en cascada Task<AuthenticationState>, que a su vez recibe el servicio DI AuthenticationStateProvider subyacente.
Recursos adicionales
- Documentación de la plataforma de identidad de Microsoft
- Temas de seguridad de ASP.NET Core
- Configurar Windows autenticación en ASP.NET Core
- Creación de una versión personalizada de la biblioteca de JavaScript Authentication.MSAL
- Autenticación y autorización de ASP.NET Core Blazor Hybrid
- GenialBlazor: Vínculos de ejemplo de la comunidad de autenticación
Los escenarios de seguridad difieren entre las aplicaciones de Blazor Server y Blazor WebAssembly. Debido a que las aplicaciones de Blazor Server se ejecutan en el servidor, las comprobaciones de autorización pueden determinar:
- Las opciones de la interfaz de usuario presentadas a un usuario (por ejemplo, qué entradas de menú están disponibles para el usuario).
- Las reglas de acceso para las áreas de la aplicación y los componentes.
Las aplicaciones de Blazor WebAssembly se ejecutan en el cliente. La autorización solo se utiliza para determinar qué opciones de la interfaz de usuario se van a mostrar. Dado que el usuario puede modificar u omitir las comprobaciones en el cliente, las aplicaciones de Blazor WebAssembly no pueden aplicar reglas de acceso de autorización.
Las convenciones de autorización de Razor Pages no se aplican a los componentes de Razor enrutables. Si se inserta un componente no enrutable de Razor en una página, las convenciones de autorización de esta afectan indirectamente al componente de Razor y al resto del contenido de la página.
Nota:
Las aplicaciones de ASP.NET Core que usan Identity de ASP.NET Core para la administración de usuarios deben utilizar Razor Pages en lugar de componentes Razor para la interfaz de usuario relacionada con la identidad, como el registro de usuarios, el inicio de sesión, el cierre de sesión y otras tareas de administración de usuarios. Identity de ASP.NET Core se ha diseñado para funcionar en un contexto de solicitud y respuesta HTTP, lo cual no está disponible con carácter general en las aplicaciones de Blazor. Las abstracciones de ASP.NET Core, como SignInManager<TUser> y UserManager<TUser>, no se admiten en los componentes Razor. Para obtener más información sobre el uso de Identity de ASP.NET Core con Blazor, consulte el documento para agregar scaffolding Identity de ASP.NET Core en una aplicación de Blazor Server.
Autenticación
Blazor usa los mecanismos de autenticación de ASP.NET Core existentes para establecer la identidad del usuario. El mecanismo exacto depende de la forma en la que se hospeda la aplicación de Blazor: Blazor WebAssembly o Blazor Server.
autenticación Blazor WebAssembly
En las aplicaciones de Blazor WebAssembly, las comprobaciones de autenticación pueden omitirse porque los usuarios pueden modificar todos los códigos del lado cliente. Lo mismo se aplica a todas las tecnologías de aplicaciones del lado cliente, incluidas las plataformas JavaScript SPA o las aplicaciones nativas para cualquier sistema operativo.
Agregue la siguiente línea de código:
Agregue una referencia de paquete para
Microsoft.AspNetCore.Components.Authorization.Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (NuGet documentación). Confirme las versiones correctas del paquete en NuGet.org.
El espacio de nombres de
Microsoft.AspNetCore.Components.Authorizational archivo_Imports.razorde la aplicación.
Para controlar la autenticación, el uso de un servicio AuthenticationStateProvider integrado o personalizado se describe en las secciones siguientes.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de ASP.NET Core Blazor WebAssembly.
autenticación Blazor Server
Las aplicaciones de Blazor Server funcionan mediante una conexión en tiempo real que se crea con SignalR. La autenticación en aplicaciones basadas en SignalR se controla cuando se establece la conexión. La autenticación se puede basar en una cookie o en cualquier otro token de portador.
El servicio AuthenticationStateProvider integrado para aplicaciones Blazor Server obtiene datos de estado de autenticación de HttpContext.User de ASP.NET Core. Así es como el estado de autenticación se integra con los mecanismos de autenticación de ASP.NET Core.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de aplicaciones de ASP.NET Core Blazor Server.
Servicio AuthenticationStateProvider
AuthenticationStateProvider es el servicio subyacente utilizado por el componente AuthorizeView y el componente CascadingAuthenticationState para obtener el estado de autenticación.
Por lo general, no se utiliza AuthenticationStateProvider directamente. Use los enfoques del componente AuthorizeView o Task<AuthenticationState> descritos más adelante en este artículo. El principal inconveniente de utilizar AuthenticationStateProvider directamente es que el componente no se notifica de manera automática si cambia el estado de autenticación subyacente de los datos.
El servicio AuthenticationStateProvider puede proporcionar los datos ClaimsPrincipal del usuario actual, como se muestra en el ejemplo siguiente:
@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
<h3>ClaimsPrincipal Data</h3>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Count() > 0)
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surnameMessage</p>
@code {
private string authMessage;
private string surnameMessage;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surnameMessage =
$"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true y porque el usuario es ClaimsPrincipal, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Para más información sobre la inserción de dependencias (DI) y servicios, consulte Inserción de dependencias de Blazor de ASP.NET Core y Inserción de dependencias en ASP.NET Core. Para obtener información sobre cómo implementar una instancia de AuthenticationStateProvider personalizada en las aplicaciones de Blazor Server, consulte Protección de aplicaciones Blazor Server de ASP.NET Core.
Exposición del estado de autenticación como un parámetro en cascada
Si se requieren los datos de estado de autenticación para la lógica de procedimiento, como cuando se realiza una acción desencadenada por el usuario, obtenga los datos de estado de autenticación mediante la definición de un parámetro en cascada del tipo Task<AuthenticationState>:
@page "/"
<button @onclick="LogUsername">Log username</button>
<p>@authMessage</p>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private string authMessage;
private async Task LogUsername()
{
var authState = await authenticationStateTask;
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Configure el parámetro en cascada Task<AuthenticationState> mediante los componentes AuthorizeRouteView y CascadingAuthenticationState en el componente App (App.razor):
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
Nota:
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, vea Migración de ASP.NET Core 3.1 a 5.0.
En una aplicación de Blazor WebAssembly, agregue servicios relativos a opciones y autorización a Program.cs:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
En una aplicación de Blazor Server, ya existen servicios para opciones y autorización, por lo que no es necesario realizar ninguna otra acción.
Autorización
Cuando un usuario está autenticado, se aplican las reglas de autorización para controlar qué puede hacer el usuario.
Por lo general, se concede o deniega el acceso en función de si:
- El usuario está autenticado (ha iniciado sesión).
- El usuario está en un rol.
- El usuario tiene una notificación.
- Una directiva se cumple.
Cada uno de estos conceptos tiene su equivalente en una aplicación ASP.NET Core MVC o Razor Pages. Para más información sobre la seguridad de ASP.NET Core, consulte los artículos disponibles en Seguridad e Identity de ASP.NET Core.
Componente AuthorizeView
El componente AuthorizeView selectivamente muestra el contenido de la interfaz de usuario dependiendo de si el usuario tiene la autorización necesaria. Este enfoque es útil cuando solo necesite mostrar datos del usuario y no es necesario usar la identidad del usuario en la lógica de procedimientos.
El componente expone una variable context del tipo AuthenticationState, que puede utilizar para acceder a la información sobre el usuario que ha iniciado sesión:
<AuthorizeView>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</AuthorizeView>
También puede proporcionar contenido diferente para mostrar si el usuario no está autorizado:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authorized.</p>
<button @onclick="SecureMethod">Authorized Only Button</button>
</Authorized>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private void SecureMethod() { ... }
}
El contenido de las etiquetas <Authorized> y <NotAuthorized> puede incluir elementos arbitrarios, como otros componentes interactivos.
Solo los usuarios autorizados pueden invocar los controladores de eventos predeterminados de un elemento autorizado, como el método SecureMethod del elemento <button> que hay en el ejemplo anterior.
Las condiciones de autorización, como los roles o directivas que controlan las opciones o el acceso a la interfaz de usuario, se tratan en la sección Autorización.
Si no se especifican las condiciones de la autorización, AuthorizeView usa una directiva predeterminada y trata:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
El componente AuthorizeView se puede usar en el componente NavMenu (Shared/NavMenu.razor) para mostrar un componente NavLink (NavLink), pero tenga en cuenta que este enfoque solo quita el elemento de lista de la salida representada. No impide que el usuario navegue hasta el componente.
Las aplicaciones creadas a partir de una plantilla de proyecto de Blazor que incluyen autenticación utilizan un componente LoginDisplay que depende de un componente AuthorizeView. El componente AuthorizeView muestra selectivamente el contenido a los usuarios para el trabajo relacionado con Identity. El ejemplo siguiente procede de la plantilla de proyecto de Blazor WebAssembly.
Shared/LoginDisplay.razor:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code{
private async Task BeginLogout(MouseEventArgs args)
{
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
El ejemplo siguiente procede de la plantilla de proyecto de Blazor Server y utiliza puntos de conexión de Identity de ASP.NET Core en el área Identity de la aplicación para procesar el trabajo relacionado con Identity.
Shared/LoginDisplay.razor:
<AuthorizeView>
<Authorized>
<a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
<form method="post" action="Identity/Account/LogOut">
<button type="submit" class="nav-link btn btn-link">Log out</button>
</form>
</Authorized>
<NotAuthorized>
<a href="Identity/Account/Register">Register</a>
<a href="Identity/Account/Login">Log in</a>
</NotAuthorized>
</AuthorizeView>
Autorización basada en roles y en directivas
El componente AuthorizeView admite la autorización basada en roles o basada en directivas.
Para la autorización basada en roles, utilice el parámetro Roles:
<AuthorizeView Roles="admin, superuser">
<p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>
Para más información, además de una guía de configuración, consulte Autorización basada en roles en ASP.NET Core.
Para la autorización basada en directivas, utilice el parámetro Policy:
<AuthorizeView Policy="content-editor">
<p>You can only see this if you satisfy the "content-editor" policy.</p>
</AuthorizeView>
La autorización basada en notificaciones es un caso especial de autorización basada en directivas. Por ejemplo, puede definir una directiva que requiere que los usuarios tengan una notificación determinada. Para obtener más información, vea Autorización basada en directivas en ASP.NET Core.
Estas API se pueden usar en aplicaciones de Blazor Server o Blazor WebAssembly.
Si no se especifica Roles ni Policy, AuthorizeView usa la directiva predeterminada.
Contenido que se muestra durante la autenticación asincrónica
Blazor permite que el estado de autenticación se determine asincrónicamente. El escenario principal de este enfoque se encuentra en las aplicaciones de Blazor WebAssembly que realizan una solicitud de autenticación a un punto de conexión externo.
Mientras la autenticación está en curso, AuthorizeView no muestra ningún contenido de forma predeterminada. Para mostrar el contenido mientras se produce autenticación, use la etiqueta <Authorizing>:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</Authorized>
<Authorizing>
<h1>Authentication in progress</h1>
<p>You can only see this content while authentication is in progress.</p>
</Authorizing>
</AuthorizeView>
Este enfoque no se aplica normalmente a las aplicaciones de Blazor Server. Las aplicaciones de Blazor Server conocen el estado de autenticación tan pronto como se establece dicho estado. El contenido Authorizing puede proporcionarse en un componente AuthorizeView de una aplicación de Blazor Server, pero nunca se muestra.
Atributo [Authorize]
El atributo [Authorize] se puede usar en los componentes de Razor:
@page "/"
@attribute [Authorize]
You can only see this if you're signed in.
Importante
Utilice únicamente [Authorize] en componentes @page a los que se llega a través del enrutador de Blazor. La autorización solo se realiza como un aspecto del enrutamiento y no para los componentes secundarios representados dentro de una página. Para autorizar la presentación de partes concretas dentro de una página, use AuthorizeView en su lugar.
El atributo [Authorize] admite también la autorización basada en roles o basada en directivas. Para la autorización basada en roles, utilice el parámetro Roles:
@page "/"
@attribute [Authorize(Roles = "admin, superuser")]
<p>You can only see this if you're in the 'admin' or 'superuser' role.</p>
Para la autorización basada en directivas, utilice el parámetro Policy:
@page "/"
@attribute [Authorize(Policy = "content-editor")]
<p>You can only see this if you satisfy the 'content-editor' policy.</p>
Si no se especifica Roles ni Policy, [Authorize] usa la directiva predeterminada, que consiste en tratar:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
Autorización de recursos
Para autorizar a los usuarios para los recursos, pase los datos de ruta de la solicitud al parámetro Resource de AuthorizeRouteView.
En el contenido de Router.Found de una ruta solicitada en el componente App (App.razor):
<AuthorizeRouteView Resource="@routeData" RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
Para obtener más información sobre cómo se pasan los datos de estado de autorización y cómo se usan en la lógica de procedimientos, consulte la sección Exposición del estado de autenticación como parámetro en cascada.
Cuando la AuthorizeRouteView recibe los datos de ruta del recurso, las directivas de autorización tienen acceso RouteData.PageType a y RouteData.RouteValues que permiten que la lógica personalizada tome decisiones de autorización.
En el ejemplo siguiente, se crea una directiva EditUser en AuthorizationOptions para la configuración del servicio de autorización de la aplicación (AddAuthorizationCore) con la lógica siguiente:
- Determine si existe un valor de ruta con una clave de
id. Si la clave existe, el valor de ruta se almacena envalue. - En una variable denominada
id, almacenevaluecomo una cadena o establezca un valor de cadena vacío (string.Empty). - Si
idno es una cadena vacía, aserte que la directiva se cumple (devuelvetrue) si el valor de la cadena comienza porEMP. De lo contrario, aserte que se produce un error en la directiva (devuelvefalse).
En Program.cs o Startup.cs (según el modelo de hospedaje y la versión del marco):
Agregue espacios de nombres de Microsoft.AspNetCore.Components y System.Linq:
using Microsoft.AspNetCore.Components; using System.Linq;Agregue la directiva:
options.AddPolicy("EditUser", policy => policy.RequireAssertion(context => { if (context.Resource is RouteData rd) { var routeValue = rd.RouteValues.TryGetValue("id", out var value); var id = Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty; if (!string.IsNullOrEmpty(id)) { return id.StartsWith("EMP", StringComparison.InvariantCulture); } } return false; }) );
El ejemplo anterior es una directiva de autorización sobreimplificada, que simplemente se usa para demostrar el concepto con un ejemplo práctico. Para obtener más información sobre la creación y configuración de directivas de autorización, vea Autorización basada en directivas en ASP.NET Core.
En el componente EditUser siguiente, el recurso en /users/{id}/edit tiene un parámetro de ruta para el identificador del usuario ({id}). El componente usa la directiva de autorización EditUser anterior para determinar si el valor de ruta de id comienza por EMP. Si id comienza por EMP, la directiva se aplica correctamente y se autoriza el acceso al componente. Si id comienza con un valor distinto de EMP o si id es una cadena vacía, se produce un error en la directiva y el componente no se carga.
Pages/EditUser.razor:
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The 'EditUser' policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string Id { get; set; }
}
Personalización del contenido no autorizado con el componente de enrutador
El componente Router, junto con el componente AuthorizeRouteView, permite que la aplicación especifique el contenido personalizado si:
- El usuario produce un error en la condición
[Authorize]aplicada al componente. Se muestra el marcado del elemento<NotAuthorized>. El atributo[Authorize]se describe en la sección Atributo[Authorize]. - La autorización asincrónica está en curso, lo que normalmente significa que el proceso de autenticación del usuario está en curso. Se muestra el marcado del elemento
<Authorizing>. - No se encuentra el contenido. Se muestra el marcado del elemento
<NotFound>.
En la plantilla de proyecto de Blazor Server predeterminada, el componente App (App.razor) muestra cómo configurar el contenido personalizado:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
<h1>Sorry</h1>
<p>You're not authorized to reach this page.</p>
<p>You may need to log in as a different user.</p>
</NotAuthorized>
<Authorizing>
<h1>Authorization in progress</h1>
<p>Only visible while authorization is in progress.</p>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, vea Migración de ASP.NET Core 3.1 a 5.0.
El contenido de las etiquetas <NotFound>, <NotAuthorized> y <Authorizing> puede incluir elementos arbitrarios, como otros componentes interactivos.
Si no se especifica la etiqueta <NotAuthorized>, AuthorizeRouteView usa el siguiente mensaje de reserva:
Not authorized.
Lógica de procedimientos
Si se requiere que la aplicación compruebe las reglas de autorización como parte de la lógica de procedimiento, utilice un parámetro en cascada del tipo Task<AuthenticationState> para obtener el ClaimsPrincipal del usuario. Task<AuthenticationState> se puede combinar con otros servicios, como IAuthorizationService, para evaluar las directivas.
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private async Task DoSomething()
{
var user = (await authenticationStateTask).User;
if (user.Identity.IsAuthenticated)
{
// Perform an action only available to authenticated (signed-in) users.
}
if (user.IsInRole("admin"))
{
// Perform an action only available to users in the 'admin' role.
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// Perform an action only available to users satisfying the
// 'content-editor' policy.
}
}
}
Nota:
En un componente de la aplicación de Blazor WebAssembly, agregue los espacios de nombres Microsoft.AspNetCore.Authorization y Microsoft.AspNetCore.Components.Authorization:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
Estos espacios de nombres se pueden proporcionar globalmente si se agregan al archivo _Imports.razor de la aplicación.
Solucionar problemas
Errores comunes:
La autorización requiere un parámetro en cascada de tipo
Task<AuthenticationState>. Considere la posibilidad de usarCascadingAuthenticationStatepara proporcionarlo.Se recibe el valor
nullparaauthenticationStateTask
Es probable que el proyecto no se haya creado mediante una plantilla de Blazor Server con la autenticación habilitada. Encapsule un <CascadingAuthenticationState> alrededor de alguna parte del árbol de la interfaz de usuario, por ejemplo, en el componente App (App.razor) de la siguiente manera:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
...
</Router>
</CascadingAuthenticationState>
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, vea Migración de ASP.NET Core 3.1 a 5.0.
El CascadingAuthenticationState proporciona el parámetro en cascada Task<AuthenticationState>, que a su vez recibe el servicio DI AuthenticationStateProvider subyacente.
Recursos adicionales
- Documentación de la plataforma de identidad de Microsoft
- Temas de seguridad de ASP.NET Core
- Configurar Windows autenticación en ASP.NET Core
- Creación de una versión personalizada de la biblioteca de JavaScript Authentication.MSAL
- GenialBlazor: Vínculos de ejemplo de la comunidad de autenticación
Los escenarios de seguridad difieren entre las aplicaciones de Blazor Server y Blazor WebAssembly. Debido a que las aplicaciones de Blazor Server se ejecutan en el servidor, las comprobaciones de autorización pueden determinar:
- Las opciones de la interfaz de usuario presentadas a un usuario (por ejemplo, qué entradas de menú están disponibles para el usuario).
- Las reglas de acceso para las áreas de la aplicación y los componentes.
Las aplicaciones de Blazor WebAssembly se ejecutan en el cliente. La autorización solo se utiliza para determinar qué opciones de la interfaz de usuario se van a mostrar. Dado que el usuario puede modificar u omitir las comprobaciones en el cliente, las aplicaciones de Blazor WebAssembly no pueden aplicar reglas de acceso de autorización.
Las convenciones de autorización de Razor Pages no se aplican a los componentes de Razor enrutables. Si se inserta un componente no enrutable de Razor en una página, las convenciones de autorización de esta afectan indirectamente al componente de Razor y al resto del contenido de la página.
Nota:
Las aplicaciones de ASP.NET Core que usan Identity de ASP.NET Core para la administración de usuarios deben utilizar Razor Pages en lugar de componentes Razor para la interfaz de usuario relacionada con la identidad, como el registro de usuarios, el inicio de sesión, el cierre de sesión y otras tareas de administración de usuarios. Identity de ASP.NET Core se ha diseñado para funcionar en un contexto de solicitud y respuesta HTTP, lo cual no está disponible con carácter general en las aplicaciones de Blazor. Las abstracciones de ASP.NET Core, como SignInManager<TUser> y UserManager<TUser>, no se admiten en los componentes Razor. Para obtener más información sobre el uso de Identity de ASP.NET Core con Blazor, consulte el documento para agregar scaffolding Identity de ASP.NET Core en una aplicación de Blazor Server.
Autenticación
Blazor usa los mecanismos de autenticación de ASP.NET Core existentes para establecer la identidad del usuario. El mecanismo exacto depende de la forma en la que se hospeda la aplicación de Blazor: Blazor WebAssembly o Blazor Server.
autenticación Blazor WebAssembly
En las aplicaciones de Blazor WebAssembly, las comprobaciones de autenticación pueden omitirse porque los usuarios pueden modificar todos los códigos del lado cliente. Lo mismo se aplica a todas las tecnologías de aplicaciones del lado cliente, incluidas las plataformas JavaScript SPA o las aplicaciones nativas para cualquier sistema operativo.
Agregue la siguiente línea de código:
Agregue una referencia de paquete para
Microsoft.AspNetCore.Components.Authorization.Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (NuGet documentación). Confirme las versiones correctas del paquete en NuGet.org.
El espacio de nombres de
Microsoft.AspNetCore.Components.Authorizational archivo_Imports.razorde la aplicación.
Para controlar la autenticación, el uso de un servicio AuthenticationStateProvider integrado o personalizado se describe en las secciones siguientes.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de ASP.NET Core Blazor WebAssembly.
autenticación Blazor Server
Las aplicaciones de Blazor Server funcionan mediante una conexión en tiempo real que se crea con SignalR. La autenticación en aplicaciones basadas en SignalR se controla cuando se establece la conexión. La autenticación se puede basar en una cookie o en cualquier otro token de portador.
El servicio AuthenticationStateProvider integrado para aplicaciones Blazor Server obtiene datos de estado de autenticación de HttpContext.User de ASP.NET Core. Así es como el estado de autenticación se integra con los mecanismos de autenticación de ASP.NET Core.
Para más información sobre cómo crear aplicaciones y su configuración, consulte Protección de aplicaciones de ASP.NET Core Blazor Server.
Servicio AuthenticationStateProvider
AuthenticationStateProvider es el servicio subyacente utilizado por el componente AuthorizeView y el componente CascadingAuthenticationState para obtener el estado de autenticación.
Por lo general, no se utiliza AuthenticationStateProvider directamente. Use los enfoques del componente AuthorizeView o Task<AuthenticationState> descritos más adelante en este artículo. El principal inconveniente de utilizar AuthenticationStateProvider directamente es que el componente no se notifica de manera automática si cambia el estado de autenticación subyacente de los datos.
El servicio AuthenticationStateProvider puede proporcionar los datos ClaimsPrincipal del usuario actual, como se muestra en el ejemplo siguiente:
@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
<h3>ClaimsPrincipal Data</h3>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Count() > 0)
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surnameMessage</p>
@code {
private string authMessage;
private string surnameMessage;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surnameMessage =
$"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true y porque el usuario es ClaimsPrincipal, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Para más información sobre la inserción de dependencias (DI) y servicios, consulte Inserción de dependencias de Blazor de ASP.NET Core y Inserción de dependencias en ASP.NET Core. Para obtener información sobre cómo implementar una instancia de AuthenticationStateProvider personalizada en las aplicaciones de Blazor Server, consulte Protección de aplicaciones Blazor Server de ASP.NET Core.
Exposición del estado de autenticación como un parámetro en cascada
Si se requieren los datos de estado de autenticación para la lógica de procedimiento, como cuando se realiza una acción desencadenada por el usuario, obtenga los datos de estado de autenticación mediante la definición de un parámetro en cascada del tipo Task<AuthenticationState>:
@page "/"
<button @onclick="LogUsername">Log username</button>
<p>@authMessage</p>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private string authMessage;
private async Task LogUsername()
{
var authState = await authenticationStateTask;
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
Si user.Identity.IsAuthenticated es true, se pueden enumerar las notificaciones y evaluar la pertenencia a roles.
Configure el parámetro en cascada Task<AuthenticationState> mediante los componentes AuthorizeRouteView y CascadingAuthenticationState en el componente App (App.razor):
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
En una aplicación de Blazor WebAssembly, agregue servicios relativos a opciones y autorización a Program.cs:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
En una aplicación de Blazor Server, ya existen servicios para opciones y autorización, por lo que no es necesario realizar ninguna otra acción.
Autorización
Cuando un usuario está autenticado, se aplican las reglas de autorización para controlar qué puede hacer el usuario.
Por lo general, se concede o deniega el acceso en función de si:
- El usuario está autenticado (ha iniciado sesión).
- El usuario está en un rol.
- El usuario tiene una notificación.
- Una directiva se cumple.
Cada uno de estos conceptos tiene su equivalente en una aplicación ASP.NET Core MVC o Razor Pages. Para más información sobre la seguridad de ASP.NET Core, consulte los artículos disponibles en Seguridad e Identity de ASP.NET Core.
Componente AuthorizeView
El componente AuthorizeView selectivamente muestra el contenido de la interfaz de usuario dependiendo de si el usuario tiene la autorización necesaria. Este enfoque es útil cuando solo necesite mostrar datos del usuario y no es necesario usar la identidad del usuario en la lógica de procedimientos.
El componente expone una variable context del tipo AuthenticationState, que puede utilizar para acceder a la información sobre el usuario que ha iniciado sesión:
<AuthorizeView>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</AuthorizeView>
También puede proporcionar contenido diferente para mostrar si el usuario no está autorizado:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authorized.</p>
<button @onclick="SecureMethod">Authorized Only Button</button>
</Authorized>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private void SecureMethod() { ... }
}
El contenido de las etiquetas <Authorized> y <NotAuthorized> puede incluir elementos arbitrarios, como otros componentes interactivos.
Solo los usuarios autorizados pueden invocar los controladores de eventos predeterminados de un elemento autorizado, como el método SecureMethod del elemento <button> que hay en el ejemplo anterior.
Las condiciones de autorización, como los roles o directivas que controlan las opciones o el acceso a la interfaz de usuario, se tratan en la sección Autorización.
Si no se especifican las condiciones de la autorización, AuthorizeView usa una directiva predeterminada y trata:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
El componente AuthorizeView se puede usar en el componente NavMenu (Shared/NavMenu.razor) para mostrar un componente NavLink (NavLink), pero tenga en cuenta que este enfoque solo quita el elemento de lista de la salida representada. No impide que el usuario navegue hasta el componente.
Las aplicaciones creadas a partir de una plantilla de proyecto de Blazor que incluyen autenticación utilizan un componente LoginDisplay que depende de un componente AuthorizeView. El componente AuthorizeView muestra selectivamente el contenido a los usuarios para el trabajo relacionado con Identity. El ejemplo siguiente procede de la plantilla de proyecto de Blazor WebAssembly.
Shared/LoginDisplay.razor:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code{
private async Task BeginLogout(MouseEventArgs args)
{
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
El ejemplo siguiente procede de la plantilla de proyecto de Blazor Server y utiliza puntos de conexión de Identity de ASP.NET Core en el área Identity de la aplicación para procesar el trabajo relacionado con Identity.
Shared/LoginDisplay.razor:
<AuthorizeView>
<Authorized>
<a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
<form method="post" action="Identity/Account/LogOut">
<button type="submit" class="nav-link btn btn-link">Log out</button>
</form>
</Authorized>
<NotAuthorized>
<a href="Identity/Account/Register">Register</a>
<a href="Identity/Account/Login">Log in</a>
</NotAuthorized>
</AuthorizeView>
Autorización basada en roles y en directivas
El componente AuthorizeView admite la autorización basada en roles o basada en directivas.
Para la autorización basada en roles, utilice el parámetro Roles:
<AuthorizeView Roles="admin, superuser">
<p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>
Para más información, además de una guía de configuración, consulte Autorización basada en roles en ASP.NET Core.
Para la autorización basada en directivas, utilice el parámetro Policy:
<AuthorizeView Policy="content-editor">
<p>You can only see this if you satisfy the "content-editor" policy.</p>
</AuthorizeView>
La autorización basada en notificaciones es un caso especial de autorización basada en directivas. Por ejemplo, puede definir una directiva que requiere que los usuarios tengan una notificación determinada. Para obtener más información, vea Autorización basada en directivas en ASP.NET Core.
Estas API se pueden usar en aplicaciones de Blazor Server o Blazor WebAssembly.
Si no se especifica Roles ni Policy, AuthorizeView usa la directiva predeterminada.
Contenido que se muestra durante la autenticación asincrónica
Blazor permite que el estado de autenticación se determine asincrónicamente. El escenario principal de este enfoque se encuentra en las aplicaciones de Blazor WebAssembly que realizan una solicitud de autenticación a un punto de conexión externo.
Mientras la autenticación está en curso, AuthorizeView no muestra ningún contenido de forma predeterminada. Para mostrar el contenido mientras se produce autenticación, use la etiqueta <Authorizing>:
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity.Name!</h1>
<p>You can only see this content if you're authenticated.</p>
</Authorized>
<Authorizing>
<h1>Authentication in progress</h1>
<p>You can only see this content while authentication is in progress.</p>
</Authorizing>
</AuthorizeView>
Este enfoque no se aplica normalmente a las aplicaciones de Blazor Server. Las aplicaciones de Blazor Server conocen el estado de autenticación tan pronto como se establece dicho estado. El contenido Authorizing puede proporcionarse en un componente AuthorizeView de una aplicación de Blazor Server, pero nunca se muestra.
Atributo [Authorize]
El atributo [Authorize] se puede usar en los componentes de Razor:
@page "/"
@attribute [Authorize]
You can only see this if you're signed in.
Importante
Utilice únicamente [Authorize] en componentes @page a los que se llega a través del enrutador de Blazor. La autorización solo se realiza como un aspecto del enrutamiento y no para los componentes secundarios representados dentro de una página. Para autorizar la presentación de partes concretas dentro de una página, use AuthorizeView en su lugar.
El atributo [Authorize] admite también la autorización basada en roles o basada en directivas. Para la autorización basada en roles, utilice el parámetro Roles:
@page "/"
@attribute [Authorize(Roles = "admin, superuser")]
<p>You can only see this if you're in the 'admin' or 'superuser' role.</p>
Para la autorización basada en directivas, utilice el parámetro Policy:
@page "/"
@attribute [Authorize(Policy = "content-editor")]
<p>You can only see this if you satisfy the 'content-editor' policy.</p>
Si no se especifica Roles ni Policy, [Authorize] usa la directiva predeterminada, que consiste en tratar:
- A los usuarios autenticados (con sesión iniciada) como autorizados.
- A los usuarios no autenticados (sin sesión no iniciada) como no autorizados.
Personalización del contenido no autorizado con el componente de enrutador
El componente Router, junto con el componente AuthorizeRouteView, permite que la aplicación especifique el contenido personalizado si:
- El usuario produce un error en la condición
[Authorize]aplicada al componente. Se muestra el marcado del elemento<NotAuthorized>. El atributo[Authorize]se describe en la sección Atributo[Authorize]. - La autorización asincrónica está en curso, lo que normalmente significa que el proceso de autenticación del usuario está en curso. Se muestra el marcado del elemento
<Authorizing>. - No se encuentra el contenido. Se muestra el marcado del elemento
<NotFound>.
En la plantilla de proyecto de Blazor Server predeterminada, el componente App (App.razor) muestra cómo configurar el contenido personalizado:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
<h1>Sorry</h1>
<p>You're not authorized to reach this page.</p>
<p>You may need to log in as a different user.</p>
</NotAuthorized>
<Authorizing>
<h1>Authorization in progress</h1>
<p>Only visible while authorization is in progress.</p>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
El contenido de las etiquetas <NotFound>, <NotAuthorized> y <Authorizing> puede incluir elementos arbitrarios, como otros componentes interactivos.
Si no se especifica la etiqueta <NotAuthorized>, AuthorizeRouteView usa el siguiente mensaje de reserva:
Not authorized.
Lógica de procedimientos
Si se requiere que la aplicación compruebe las reglas de autorización como parte de la lógica de procedimiento, utilice un parámetro en cascada del tipo Task<AuthenticationState> para obtener el ClaimsPrincipal del usuario. Task<AuthenticationState> se puede combinar con otros servicios, como IAuthorizationService, para evaluar las directivas.
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private async Task DoSomething()
{
var user = (await authenticationStateTask).User;
if (user.Identity.IsAuthenticated)
{
// Perform an action only available to authenticated (signed-in) users.
}
if (user.IsInRole("admin"))
{
// Perform an action only available to users in the 'admin' role.
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// Perform an action only available to users satisfying the
// 'content-editor' policy.
}
}
}
Nota:
En un componente de la aplicación de Blazor WebAssembly, agregue los espacios de nombres Microsoft.AspNetCore.Authorization y Microsoft.AspNetCore.Components.Authorization:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
Estos espacios de nombres se pueden proporcionar globalmente si se agregan al archivo _Imports.razor de la aplicación.
Solucionar problemas
Errores comunes:
La autorización requiere un parámetro en cascada de tipo
Task<AuthenticationState>. Considere la posibilidad de usarCascadingAuthenticationStatepara proporcionarlo.Se recibe el valor
nullparaauthenticationStateTask
Es probable que el proyecto no se haya creado mediante una plantilla de Blazor Server con la autenticación habilitada. Encapsule un <CascadingAuthenticationState> alrededor de alguna parte del árbol de la interfaz de usuario, por ejemplo, en el componente App (App.razor) de la siguiente manera:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
...
</Router>
</CascadingAuthenticationState>
El CascadingAuthenticationState proporciona el parámetro en cascada Task<AuthenticationState>, que a su vez recibe el servicio DI AuthenticationStateProvider subyacente.