Autorización basada en notificaciones en ASP.NET Core

Cuando se crea una identidad, se le puede asignar una o varias notificaciones emitidas por una entidad de confianza. Una notificación es un par de valor y nombre que representa lo que es el sujeto, no lo que puede hacer. Por ejemplo, puede tener un permiso de conducir, expedido por una autoridad local competente en materia de permisos de conducir. En su permiso de conducir figura su fecha de nacimiento. En este caso, el nombre de la notificación sería DateOfBirth, el valor de la notificación sería su fecha de nacimiento, por ejemplo 8th June 1970, y el emisor sería la autoridad competente en materia de permisos de conducción. La autorización basada en notificaciones, en su forma más sencilla, comprueba el valor de una notificación y permite el acceso a un recurso basado en ese valor. Por ejemplo, si desea acceder a un club nocturno, el proceso de autorización podría ser:

El vigilante de seguridad de la puerta evaluaría el valor de su notificación de fecha de nacimiento y si confía en el emisor (la autoridad que expide el permiso de conducir) antes de concederle el acceso.

Una identidad puede contener varias notificaciones con varios valores y puede contener varias notificaciones del mismo tipo.

Agregar comprobaciones de notificaciones

Comprobaciones de autorización basadas en notificaciones:

  • Son declarativas.
  • Se aplican a Páginas de Razor, controladores o acciones dentro de un controlador.
  • No se puede aplicar a nivel de controlador de Página de Razor, deben aplicarse a la página.

Las notificaciones en el código especifican las notificaciones que el usuario actual debe poseer y, opcionalmente, el valor que la notificación debe contener para acceder al recurso solicitado. Los requisitos de notificaciones se basan en directivas, el desarrollador debe compilar y registrar una directiva que exprese los requisitos de notificaciones.

El tipo más sencillo de directiva de notificación busca la presencia de una notificación y no comprueba el valor.

Compilar y registrar la directiva y llamar a UseAuthorization. El registro de la directiva tiene lugar como parte de la configuración del servicio de autorización, normalmente en el archivo Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
   options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

En este caso, la directiva de EmployeeOnly comprueba la presencia de una notificación de EmployeeNumber en la identidad actual.

Aplique la directiva mediante la propiedad Policy en el atributo [Authorize] para especificar el nombre de la directiva.

[Authorize(Policy = "EmployeeOnly")]
public IActionResult VacationBalance()
{
    return View();
}

El atributo [Authorize] se puede aplicar a un controlador completo o a una Página de Razor, en esta instancia, solo las identidades que coincidan con la directiva pueden acceder a cualquier acción del controlador.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    public ActionResult VacationBalance()
    {
        return View();
    }

    [AllowAnonymous]
    public ActionResult VacationPolicy()
    {
        return View();
    }
}

El siguiente código aplica el atributo [Authorize] a una Página de Razor:

[Authorize(Policy = "EmployeeOnly")]
public class IndexModel : PageModel
{
    public void OnGet()
    {

    }
}

Las directivas no pueden aplicarse a nivel de controlador de Página de Razor, deben aplicarse a la página.

Si tiene un controlador protegido por el atributo [Authorize], pero desea permitir el acceso anónimo a acciones concretas, aplique el atributo AllowAnonymousAttribute.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    public ActionResult VacationBalance()
    {
        return View();
    }

    [AllowAnonymous]
    public ActionResult VacationPolicy()
    {
        return View();
    }
}

Dado que las directivas no se pueden aplicar en el nivel de controlador de Páginas de Razor, se recomienda usar un controlador cuando se deben aplicar las directivas en el nivel de controlador de páginas. El resto de la aplicación que no requiere directivas en el nivel de controlador de Páginas de Razor puede usar Páginas de Razor.

La mayoría de las notificaciones vienen con un valor. Puede especificar una lista de valores permitidos al crear la directiva. El siguiente ejemplo solo sería válido para los empleados cuyo número de empleado fuera 1, 2, 3, 4 ó 5.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Founders", policy =>
                      policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Agregar una comprobación de notificación genérica

Si el valor de notificación no es un valor único o se requiere una transformación, use RequireAssertion. Para obtener más información, consulte Usar funciones para cumplir una directiva.

Evaluación de varias directivas

Si se aplican varias directivas en los niveles de controlador y acción, todas las directivas deben pasar antes de que se conceda acceso:

[Authorize(Policy = "EmployeeOnly")]
public class SalaryController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Payslip()
    {
        return View();
    }

    [Authorize(Policy = "HumanResources")]
    public IActionResult UpdateSalary()
    {
        return View();
    }
}

En el ejemplo anterior, cualquier identidad que cumpla la directiva de EmployeeOnlypuede acceder a la acción de Payslip a medida que se aplica esa directiva en el controlador. Sin embargo, para poder llamar a la acción de UpdateSalary, la identidad debe cumplir tanto la directiva de EmployeeOnly como la directiva de HumanResources.

Si desea directivas más complicadas, como tomar una notificación de fecha de nacimiento, calcular una edad a partir de ella y comprobar que la edad es de 21 años o más, tendrá que escribir controladores de directivas personalizados.

En el ejemplo siguiente, ambos métodos de controlador de página deben cumplir tanto la directiva de EmployeeOnly como la directiva de HumanResources:

[Authorize(Policy = "EmployeeOnly")]
[Authorize(Policy = "HumanResources")]
public class SalaryModel : PageModel
{
    public ContentResult OnGetPayStub()
    {
        return Content("OnGetPayStub");
    }

    public ContentResult OnGetSalary()
    {
        return Content("OnGetSalary");
    }
}

Cuando se crea una identidad, se le puede asignar una o varias notificaciones emitidas por una entidad de confianza. Una notificación es un par de valor y nombre que representa lo que es el sujeto, no lo que puede hacer. Por ejemplo, puede tener un permiso de conducir, expedido por una autoridad local competente en materia de permisos de conducir. En su permiso de conducir figura su fecha de nacimiento. En este caso, el nombre de la notificación sería DateOfBirth, el valor de la notificación sería su fecha de nacimiento, por ejemplo 8th June 1970, y el emisor sería la autoridad competente en materia de permisos de conducción. La autorización basada en notificaciones, en su forma más sencilla, comprueba el valor de una notificación y permite el acceso a un recurso basado en ese valor. Por ejemplo, si desea acceder a un club nocturno, el proceso de autorización podría ser:

El vigilante de seguridad de la puerta evaluaría el valor de su notificación de fecha de nacimiento y si confía en el emisor (la autoridad que expide el permiso de conducir) antes de concederle el acceso.

Una identidad puede contener varias notificaciones con varios valores y puede contener varias notificaciones del mismo tipo.

Agregar comprobaciones de notificaciones

Las comprobaciones de autorización basadas en notificaciones son declarativas: el desarrollador las incorpora dentro de su código, contra un controlador o una acción dentro de un controlador, especificando las notificaciones que debe poseer el usuario actual y, opcionalmente, el valor que debe tener la notificación para acceder al recurso solicitado. Los requisitos de notificaciones se basan en directivas, el desarrollador debe compilar y registrar una directiva que exprese los requisitos de notificaciones.

El tipo más sencillo de directiva de notificación busca la presencia de una notificación y no comprueba el valor.

Compilar y registrar la directiva. Esto tiene lugar como parte de la configuración del servicio de autorización, que normalmente participa en ConfigureServices() en el archivo Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
    });
}

Llame a UseAuthorization en Configure. El siguiente código se genera mediante las plantillas de aplicación web de ASP.NET Core:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

En este caso, la directiva de EmployeeOnly comprueba la presencia de una notificación de EmployeeNumber en la identidad actual.

A continuación, aplica la directiva mediante la propiedad Policy en el atributo [Authorize] para especificar el nombre de la directiva;

[Authorize(Policy = "EmployeeOnly")]
public IActionResult VacationBalance()
{
    return View();
}

El atributo [Authorize] se puede aplicar a un controlador completo, en esta instancia, solo las identidades que coincidan con la directiva podrán acceder a cualquier acción del controlador.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public ActionResult VacationBalance()
    {
    }
}

Si tiene un controlador protegido por el atributo [Authorize], pero desea permitir el acceso anónimo a acciones concretas, aplique el atributo AllowAnonymousAttribute.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public ActionResult VacationBalance()
    {
    }

    [AllowAnonymous]
    public ActionResult VacationPolicy()
    {
    }
}

La mayoría de las notificaciones vienen con un valor. Puede especificar una lista de valores permitidos al crear la directiva. El siguiente ejemplo solo sería válido para los empleados cuyo número de empleado fuera 1, 2, 3, 4 ó 5.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("Founders", policy =>
                          policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
    });
}

Agregar una comprobación de notificación genérica

Si el valor de notificación no es un valor único o se requiere una transformación, use RequireAssertion. Para obtener más información, consulte Usar funciones para cumplir una directiva.

Evaluación de varias directivas

Si aplica varias directivas a un controlador o acción, todas las directivas deben pasar antes de que se conceda acceso. Por ejemplo:

[Authorize(Policy = "EmployeeOnly")]
public class SalaryController : Controller
{
    public ActionResult Payslip()
    {
    }

    [Authorize(Policy = "HumanResources")]
    public ActionResult UpdateSalary()
    {
    }
}

En el ejemplo anterior, cualquier identidad que cumpla la directiva de EmployeeOnlypuede acceder a la acción de Payslip a medida que se aplica esa directiva en el controlador. Sin embargo, para poder llamar a la acción de UpdateSalary, la identidad debe cumplir tanto la directiva de EmployeeOnly como la directiva de HumanResources.

Si desea directivas más complicadas, como tomar una notificación de fecha de nacimiento, calcular una edad a partir de ella y comprobar que la edad es de 21 años o más, tendrá que escribir controladores de directivas personalizados.

Cuando se crea una identidad, se le puede asignar una o varias notificaciones emitidas por una entidad de confianza. Una notificación es un par de valor y nombre que representa lo que es el sujeto, no lo que puede hacer. Por ejemplo, puede tener un permiso de conducir, expedido por una autoridad local competente en materia de permisos de conducir. En su permiso de conducir figura su fecha de nacimiento. En este caso, el nombre de la notificación sería DateOfBirth, el valor de la notificación sería su fecha de nacimiento, por ejemplo 8th June 1970, y el emisor sería la autoridad competente en materia de permisos de conducción. La autorización basada en notificaciones, en su forma más sencilla, comprueba el valor de una notificación y permite el acceso a un recurso basado en ese valor. Por ejemplo, si desea acceder a un club nocturno, el proceso de autorización podría ser:

El vigilante de seguridad de la puerta evaluaría el valor de su notificación de fecha de nacimiento y si confía en el emisor (la autoridad que expide el permiso de conducir) antes de concederle el acceso.

Una identidad puede contener varias notificaciones con varios valores y puede contener varias notificaciones del mismo tipo.

Agregar comprobaciones de notificaciones

Las comprobaciones de autorización basadas en notificaciones son declarativas: el desarrollador las incorpora dentro de su código, contra un controlador o una acción dentro de un controlador, especificando las notificaciones que debe poseer el usuario actual y, opcionalmente, el valor que debe tener la notificación para acceder al recurso solicitado. Los requisitos de notificaciones se basan en directivas, el desarrollador debe compilar y registrar una directiva que exprese los requisitos de notificaciones.

El tipo más sencillo de directiva de notificación busca la presencia de una notificación y no comprueba el valor.

Compilar y registrar la directiva. Esto tiene lugar como parte de la configuración del servicio de autorización, que normalmente participa en ConfigureServices() en el archivo Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
    });
}

En este caso, la directiva de EmployeeOnly comprueba la presencia de una notificación de EmployeeNumber en la identidad actual.

A continuación, aplica la directiva mediante la propiedad Policy en el atributo [Authorize] para especificar el nombre de la directiva;

[Authorize(Policy = "EmployeeOnly")]
public IActionResult VacationBalance()
{
    return View();
}

El atributo [Authorize] se puede aplicar a un controlador completo, en esta instancia, solo las identidades que coincidan con la directiva podrán acceder a cualquier acción del controlador.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public ActionResult VacationBalance()
    {
    }
}

Si tiene un controlador protegido por el atributo [Authorize], pero desea permitir el acceso anónimo a acciones concretas, aplique el atributo AllowAnonymousAttribute.

[Authorize(Policy = "EmployeeOnly")]
public class VacationController : Controller
{
    public ActionResult VacationBalance()
    {
    }

    [AllowAnonymous]
    public ActionResult VacationPolicy()
    {
    }
}

La mayoría de las notificaciones vienen con un valor. Puede especificar una lista de valores permitidos al crear la directiva. El siguiente ejemplo solo sería válido para los empleados cuyo número de empleado fuera 1, 2, 3, 4 ó 5.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("Founders", policy =>
                          policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
    });
}

Agregar una comprobación de notificación genérica

Si el valor de notificación no es un valor único o se requiere una transformación, use RequireAssertion. Para obtener más información, consulte Usar funciones para cumplir una directiva.

Evaluación de varias directivas

Si aplica varias directivas a un controlador o acción, todas las directivas deben pasar antes de que se conceda acceso. Por ejemplo:

[Authorize(Policy = "EmployeeOnly")]
public class SalaryController : Controller
{
    public ActionResult Payslip()
    {
    }

    [Authorize(Policy = "HumanResources")]
    public ActionResult UpdateSalary()
    {
    }
}

En el ejemplo anterior, cualquier identidad que cumpla la directiva de EmployeeOnlypuede acceder a la acción de Payslip a medida que se aplica esa directiva en el controlador. Sin embargo, para poder llamar a la acción de UpdateSalary, la identidad debe cumplir tanto la directiva de EmployeeOnly como la directiva de HumanResources.

Si desea directivas más complicadas, como tomar una notificación de fecha de nacimiento, calcular una edad a partir de ella y comprobar que la edad es de 21 años o más, tendrá que escribir controladores de directivas personalizados.