Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Una directiva de autorización de ASP.NET Core es un conjunto con nombre de uno o varios requisitos de autorización que el marco evalúa para decidir si un usuario puede acceder a un recurso.
En este artículo, se explica lo siguiente:
- Cómo crear requisitos.
- Cómo registrar y aplicar directivas.
- Controladores de autorización para la evaluación de requisitos únicos y múltiples.
- Cómo se evalúan varios requisitos en una sola directiva.
En la práctica, una directiva se aplica a [Authorize(Policy = "...")] (Razor componentes, páginas y controladores) o a RequireAuthorization(...) (puntos de conexión), y el framework usa manejadores para evaluar los requisitos de una directiva.
IAuthorizationPolicyProvider(Proveedores de directivas de autorización personalizadas en ASP.NET Core documentación) genera directivas dinámicamente en lugar de registrarlas en el inicio de la aplicación.
La autorización basada en roles y la autorización basada en claims usan un requisito, un controlador de requisitos y una política de autorización preconfigurada. Estos bloques de creación admiten la expresión de evaluaciones de autorización en el código.
En este artículo se usan ejemplos de componentes de Razor y se centra en escenarios de autorización de Blazor para ASP.NET Core 3.1 o posterior. Para obtener Razor instrucciones de Pages y MVC que se aplican a todas las versiones de ASP.NET Core, consulte los siguientes recursos después de leer este artículo:
- Autorización basada en directivas en páginas de ASP.NET Core Razor
- Autorización basada en directivas en ASP.NET Core MVC
Algunos ejemplos de este artículo (ASP.NET Core 8.0 o posterior) usan constructores principales, disponibles en C# 12 (.NET 8) o versiones posteriores. Para obtener más información, vea Declarar constructores principales para clases y estructuras (tutorial de documentación de C#) y constructores principales (Guía de C#).
Requisitos y registro de directivas
Una directiva de autorización consta de uno o varios requisitos, que la directiva utiliza para evaluar la autorización de la identidad del usuario actual. Un requisito implementa IAuthorizationRequirement, que es una interfaz de marcador vacía.
Cuando un requisito no contiene datos o tiene propiedades (parámetros), actúa como un marcador vacío para desencadenar un controlador de autorización asociado (IAuthorizationHandler) para procesar la autorización (que se describe en detalle más adelante en este artículo). Dado que el controlador en este caso se basa completamente en el contexto HTTP, las notificaciones del usuario o los datos de back-end para tomar una decisión sobre el usuario que cumple el requisito, la propia clase de requisito no requiere datos o parámetros internos. El requisito solo indica al framework qué regla debe evaluar.
Por ejemplo, considere el siguiente requisito mínimo de edad (MinimumAgeRequirement), que se implementa simplemente como una clase de marcador:
public class MinimumAgeRequirement : IAuthorizationRequirement { }
El requisito anterior se usa para crear una directiva que confirme que el usuario supera una antigüedad específica que comprueba el controlador. Un AuthorizationHandler<MinimumAgeRequirement> examina el AuthorizationHandlerContext.User. Si el usuario tiene un atributo de fecha de nacimiento que indica que supera una determinada edad, el requisito se cumple. El objeto de requisito no requiere ninguna propiedad (parámetros) en este caso. En el ejemplo siguiente se muestra la implementación completa de un requisito de antigüedad mínima que tiene un parámetro para establecer la edad mínima.
Tenga en cuenta el siguiente MinimumAgeRequirement requisito, que describe un único parámetro, una edad mínima, para evaluar la autorización del usuario:
using Microsoft.AspNetCore.Authorization;
namespace BlazorWebAppAuthorization.Policies.Requirements;
public class MinimumAgeRequirement(int minimumAge) : IAuthorizationRequirement
{
public int MinimumAge { get; } = minimumAge;
}
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int minimumAge) =>
MinimumAge = minimumAge;
public int MinimumAge { get; }
}
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
Una directiva se registra como parte de la configuración del servicio de autorización en el archivo Program de la aplicación mediante una llamada a AuthorizationBuilder.AddPolicy. En el ejemplo siguiente se crea una AtLeast21 directiva con un único requisito de una edad mínima y se establece la edad mínima en 21 años.
builder.Services.AddAuthorizationBuilder()
.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
Una directiva se registra como parte de la configuración del servicio de autorización en el archivo Program de la aplicación mediante una llamada a AuthorizationBuilder.AddPolicy. En el ejemplo siguiente se crea una AtLeast21 directiva con un único requisito de una edad mínima y se establece la edad mínima en 21 años:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
Una directiva se registra como parte de la configuración del servicio de autorización en Startup.ConfigureServices (Startup.cs) llamando a AuthorizationBuilder.AddPolicy. En el ejemplo siguiente se crea una AtLeast21 directiva con un único requisito de una edad mínima y se establece la edad mínima en 21 años:
services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
Si una directiva de autorización contiene varios requisitos de autorización, todos los requisitos deben pasar para que la evaluación de la directiva se realice correctamente. En otras palabras, varios requisitos de autorización agregados a una sola directiva de autorización se consideran en base a una lógica AND.
Aplicación de directivas a Razor componentes
Aplique políticas a los componentes Razor mediante el atributo [Authorize] con el nombre de la política:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]
Si se aplican varias directivas, todas las directivas deben pasarse antes de conceder acceso:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]
@attribute [Authorize(Policy = "HumanResourcesMember")]
Aplicación de directivas a puntos de conexión
Aplique las directivas a los puntos de conexión usando RequireAuthorization con el nombre de la directiva. Por ejemplo:
app.MapGet("/helloworld", () => "Hello World!")
.RequireAuthorization("AtLeast21");
Aplicación de directivas en aplicaciones de MVC y Razor Pages
Para obtener instrucciones sobre cómo aplicar directivas en Razor las aplicaciones Pages y MVC, consulte los siguientes recursos:
- Autorización basada en directivas en páginas de ASP.NET Core Razor
- Autorización basada en directivas en ASP.NET Core MVC
Interfaz de servicio de autorización (IAuthorizationService)
IAuthorizationService es el principal responsable de determinar si la autorización se realiza con éxito cuando se llama a una sobrecarga de IAuthorizationService.AuthorizeAsync:
-
AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements): comprueba si un usuario cumple un conjunto específico de requisitos de autorización para un recurso especificado. -
AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName): comprueba si un usuario cumple una directiva de autorización específica para un recurso especificado.
Si no se requiere un recurso para evaluar directivas, se pasa null como recurso.
Los métodos anteriores devuelven un AuthorizationResult envuelto en un Task.
Cada IAuthorizationHandler es responsable de verificar si se cumplen los requisitos mediante IAuthorizationHandler.HandleAsync. La AuthorizationHandlerContext clase contiene la información de autorización utilizada por la IAuthorizationHandler implementación. IAuthorizationRequirement es una interfaz de marcador sin métodos que actúen como mecanismo para realizar el seguimiento de si la autorización es correcta. Cuando AuthorizationHandlerContext.Succeed se llama con IAuthorizationRequirement, se cumple la política:
context.Succeed(requirement);
Controladores de autorización
Un controlador de autorización es responsable de la evaluación de las propiedades de un requisito. El controlador de autorización evalúa los requisitos con respecto a un AuthorizationHandlerContext proporcionado para determinar si se permite el acceso.
Un requisito puede tener varios controladores. Un controlador puede heredar AuthorizationHandler<TRequirement>, donde TRequirement es el requisito de controlar. Como alternativa, un controlador puede implementar IAuthorizationHandler directamente para controlar más de un tipo de requisito.
Uso de un controlador para un requisito
En el ejemplo siguiente se muestra una relación uno a uno en la que un controlador de edad mínima controla un único requisito:
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.Policies.Handlers;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
var dateOfBirthClaim =
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth);
if (dateOfBirthClaim is null)
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
var dateOfBirthClaim =
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth);
if (dateOfBirthClaim is null)
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
// Use the following if targeting a version of
// .NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
// Use the following if targeting a version of
// .NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
El código anterior determina si el principal de usuario actual tiene una declaración de fecha de nacimiento. La autorización no se puede producir cuando falta la notificación, en cuyo caso se devuelve una tarea completada. Cuando hay una reclamación, se calcula la edad del usuario. Si el usuario cumple la edad mínima definida por el requisito, la autorización se considera correcta. Cuando la autorización se realiza correctamente, context.Succeed se invoca con el requisito satisfecho como único parámetro.
Uso de un controlador para varios requisitos
En el ejemplo siguiente se muestra una relación uno a varios en la que un controlador de permisos puede controlar tres tipos diferentes de requisitos:
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.Policies.Handlers;
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadPermission)
{
if (IsOwner(context.User, context.Resource)
|| IsSponsor(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditPermission || requirement is DeletePermission)
{
if (IsOwner(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
return Task.CompletedTask;
}
private static bool IsOwner(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
private static bool IsSponsor(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
}
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadPermission)
{
if (IsOwner(context.User, context.Resource) ||
IsSponsor(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditPermission ||
requirement is DeletePermission)
{
if (IsOwner(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
// Use the following if targeting a version of
// .NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
private bool IsOwner(ClaimsPrincipal user, object resource)
{
// Code omitted for brevity
return true;
}
private bool IsSponsor(ClaimsPrincipal user, object resource)
{
// Code omitted for brevity
return true;
}
}
El código anterior atraviesa PendingRequirements: una propiedad que contiene requisitos no marcados como exitosos. Para un requisito de ReadPermission, el usuario debe ser el propietario o patrocinador para acceder al recurso solicitado. Para un requisito de EditPermission o DeletePermission, deben ser los propietarios para acceder al recurso solicitado.
Registro del controlador
Registre controladores en la colección de servicios durante la configuración. En el ejemplo siguiente se registra un controlador de antigüedad mínimo (MinimumAgeHandler) como servicio singleton, pero se puede registrar un controlador mediante cualquiera de las duraciones de servicio integradas:
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
Es posible agrupar un requisito y un controlador en una sola clase que implemente IAuthorizationRequirement y IAuthorizationHandler. Esta agrupación crea un acoplamiento estricto entre el controlador y el requisito y solo se recomienda para los requisitos y controladores simples. Crear una clase que implemente ambas interfaces elimina la necesidad de registrar el manejador en el contenedor de servicios gracias a la funcionalidad integrada PassThroughAuthorizationHandler, que permite que los requisitos se administren por sí mismos.
Consulte la implementación de la clase AssertionRequirement de ASP.NET Core para ver un ejemplo donde el AssertionRequirement es tanto un requisito como el controlador en una clase completamente autocontenida. La API del marco AssertionRequirement le permite validar el acceso mediante expresiones lambda en línea en lugar de escribir clases independientes de requisitos y controladores de requisitos repetitivos.
Note
Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta para una versión específica, use la lista desplegable Cambiar ramas o etiquetas . Para obtener más información, vea Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).
¿Qué debe devolver un controlador?
El Handle método del ejemplo del controlador no devuelve ningún valor. ¿Cómo se indica un estado de éxito o error?
Un controlador indica que se ha realizado correctamente llamando a
context.Succeed, pasando el requisito validado correctamente (IAuthorizationRequirement).Por regla general, no se requiere que un manejador gestione los errores, ya que otros manejadores para el mismo requisito pueden tener éxito.
Para garantizar el fracaso, incluso si otros gestores de requisitos tienen éxito, llame a
context.Fail.
Si un controlador llama a context.Succeed o context.Fail, se sigue llamando a todos los demás controladores. Esto permite que los requisitos produzcan efectos secundarios, como el registro, que tiene lugar incluso si otro controlador valida correctamente o produce un error en un requisito. Cuando se establece en false, la propiedad InvokeHandlersAfterFailure interrumpe la ejecución de controladores cuando se llama a context.Fail. El valor predeterminado de InvokeHandlersAfterFailure es true, en cuyo caso se llama a todos los controladores.
Note
Se llama a los controladores de autorización incluso si se produce un error en la autenticación. Además, los controladores pueden ejecutarse en cualquier orden, por lo que no dependen del orden de llamar a los controladores.
¿Por qué necesitaría varios manejadores para un requisito?
En los casos en los que quiera que la evaluación sea en función de OR, implemente varios controladores para un único requisito. Por ejemplo, supongamos que Contoso Corporation tiene puertas que solo se abren con tarjetas de clave. Si dejas tu tarjeta de llave en casa, el recepcionista imprime una pegatina temporal y abre la puerta para ti. En este escenario, la aplicación tiene un único requisito, pero varios controladores, cada uno examinando un único requisito.
En las implementaciones de ejemplo siguientes:
-
BuildingEntryRequirementes el requisito de acceso al edificio. -
BadgeEntryHandler(el individuo tiene un distintivo) yTemporaryStickerHandler(el individuo tiene una pegatina temporal) son controladores independientes, cada uno examinando un único requisito.
BuildingEntryRequirement.cs:
using Microsoft.AspNetCore.Authorization;
namespace BlazorWebAppAuthorization.Policies.Requirements;
public class BuildingEntryRequirement : IAuthorizationRequirement { }
BadgeEntryHandler.cs:
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.Policies.Handlers;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "BadgeId"))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
TemporaryStickerHandler.cs:
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.Policies.Handlers;
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "TemporaryBadgeId" &&
c.Issuer == "https://contososecurity"))
{
// Code to check expiration date omitted for brevity.
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
BuildingEntryRequirement.cs:
using Microsoft.AspNetCore.Authorization;
public class BuildingEntryRequirement : IAuthorizationRequirement
{
}
BadgeEntryHandler.cs:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "BadgeId" &&
c.Issuer == "https://contososecurity"))
{
context.Succeed(requirement);
}
// Use the following if targeting a version of
// .NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
TemporaryStickerHandler.cs:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "TemporaryBadgeId" &&
c.Issuer == "https://contososecurity"))
{
// We'd also check the expiration date on the sticker.
context.Succeed(requirement);
}
// Use the following if targeting a version of
// .NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
Asegúrese de que ambos controladores están registrados. Si cualquiera de los manejadores tiene éxito cuando una directiva evalúa el BuildingEntryRequirement, la evaluación de la directiva tiene éxito.
Usa Func para cumplir una directiva
Hay situaciones en las que el cumplimiento de una directiva es fácil de expresar en el código con un Func<AuthorizationHandlerContext, bool> delegado al configurar una directiva con el RequireAssertion generador de directivas. Por ejemplo, el anterior BadgeEntryHandler se puede volver a escribir de la siguiente manera:
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
(c.Type == "BadgeId" || c.Type == "TemporaryBadgeId")
&& c.Issuer == "https://contososecurity")));
});
// <snippet_minimumAgeHandlerRegistration>
services.AddAuthorization(options =>
{
options.AddPolicy("BadgeEntry", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c =>
(c.Type == "BadgeId" ||
c.Type == "TemporaryBadgeId") &&
c.Issuer == "https://microsoftsecurity")));
});
Requerir autenticación de usuario global
Para obtener información sobre cómo requerir autenticación para todos los usuarios de la aplicación, consulte Crear una aplicación de ASP.NET Core con datos de usuario protegidos por autorización.
Autorización a través de un ejemplo de servicio externo
La autorización a través de un ejemplo de servicio externo (dotnet/AspNetCore.Docs.Samples GitHub repositorio) muestra cómo implementar requisitos de autorización adicionales con un servicio de autorización externo. El proyecto de la Contoso.API solución está protegido con Microsoft Entra ID. Una comprobación de autorización adicional del proyecto Contoso.Security.API devuelve una carga que describe si la aplicación cliente Contoso.API puede invocar la API GetWeather.
Configuración del ejemplo
La siguiente demostración se basa en el uso de NSwag (Swagger/OpenAPI) o cURL en un shell de comandos.
En el proyecto Contoso.Security.API, establezca el marcador de posición AllowedClients ({CLIENT ID}) con cualquier valor GUID de prueba (por ejemplo, 00001111-aaaa-2222-bbbb-3333cccc4444):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AllowedClients": [
"{CLIENT ID (FOR THE CLIENT CALLING CONTOSO.API)}"
]
}
En un intérprete de comandos abierto en el proyecto Contoso.API, use dotnet user-jwts para generar un token de acceso con una declaración appid para el identificador de la aplicación cliente, creado en el paso anterior (por ejemplo, 00001111-aaaa-2222-bbbb-3333cccc4444).
dotnet user-jwts create --claim appid={GUID}
Ejemplo:
dotnet user-jwts create --claim appid=00001111-aaaa-2222-bbbb-3333cccc4444
La salida genera un token después de "Token:" en el shell de comandos:
New JWT saved with ID '{JWT ID}'.
Name: {USER}
Custom Claims: [appid=00001111-aaaa-2222-bbbb-3333cccc4444]
Token: {TOKEN}
Establezca el valor del token (donde aparece el marcador de posición {TOKEN} en la salida anterior) y guárdelo para usarlo más adelante.
Puede descodificar el token en un descodificador en línea JWT , como jwt.ms para ver su contenido, revelando que contiene una appid notificación con el identificador de la aplicación cliente:
{
"alg": "HS256",
"typ": "JWT"
}.{
"unique_name": "{USER}",
"sub": "{USER}",
"jti": "14ed7729",
"appid": "{CLIENT ID}",
"aud": [
"https://localhost:7250",
"http://localhost:7251"
],
"nbf": 1780660887,
"exp": 1788609687,
"iat": 1780660888,
"iss": "dotnet-user-jwts"
}.[Signature]
Vuelva a ejecutar el comando con un valor incorrecto de identificador de cliente (appid):
dotnet user-jwts create --claim appid=aaaabbbb-0000-cccc-1111-dddd2222eeee
Establezca el valor del segundo token por separado.
Inicie los proyectos Contoso.API y Contoso.Security.API en Visual Studio o con el comando dotnet watch en una consola de comandos:
dotnet watch
En la interfaz de usuario de Swagger del Contoso.API proyecto (https://localhost:7250/swagger/index.html), seleccione el botón Autorizar .
En la ventana Autorizaciones disponibles: Bearer , escriba el token de acceso. Seleccione el botón Autorizar. Cierre la ventana Autorizaciones disponibles .
En default, seleccione el botón Get para el endpoint /WeatherForecast. Seleccione el botón Pruébelo. Seleccione el botón Ejecutar.
La salida de Respuestas>Respuesta del servidor>Cuerpo de la respuesta muestra el JSON de previsión meteorológica devuelto por el proyecto Contoso.API.
Realice los mismos pasos con el token de acceso que se generó con un identificador de aplicación cliente no válido. La respuesta es 403 - Prohibido.