tutorial tag route net mvc data asp all c# asp.net-mvc asp.net-core access-control

c# - route - tag helpers asp net core



Cómo implementar el control de acceso basado en permisos con Asp.Net Core (3)

Para obtener una solución que no requiera que agregue una política para cada permiso, vea mi answer para otra pregunta.

Le permite decorar sus Controladores y Acciones con cualquier atributo personalizado que desee, y acceder a ellos en su AuthorizationHandler.

Estoy tratando de implementar el control de acceso basado en permisos con aspnet core. Para gestionar dinámicamente los roles y permisos de usuario (create_product, delete_product, etc.), se almacenan en la base de datos. El modelo de datos es como http://i.stack.imgur.com/CHMPE.png

Antes de aspnet core (en MVC 5) estaba usando AuthorizeAttribute personalizado como a continuación para manejar el problema:

public class CustomAuthorizeAttribute : AuthorizeAttribute { private readonly string _permissionName { get; set; } [Inject] public IAccessControlService _accessControlService { get; set; } public CustomAuthorizeAttribute(string permissionName = "") { _permissionName = permissionName; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); var user = _accessControlService.GetUser(); if (PermissionName != "" && !user.HasPermission(_permissionName)) { // set error result filterContext.HttpContext.Response.StatusCode = 403; return; } filterContext.HttpContext.Items["CUSTOM_USER"] = user; } }

Luego lo estaba usando en el método de acción como a continuación:

[HttpGet] [CustomAuthorize(PermissionEnum.PERSON_LIST)] public ActionResult Index(PersonListQuery query){ }

Además, estaba usando HttpContext.Items ["CUSTOM_USER"] en las vistas para mostrar u ocultar la parte html:

@if (CurrentUser.HasPermission("<Permission Name>")) { }

Cuando decidí cambiar el núcleo de aspnet, todo mi plan falló. Porque no había un método virtual de OnAuthorization en AuthorizeAttribute . Intenté algunas formas de resolver el problema. Esos están abajo:

  • Uso de una nueva autorización basada en políticas (creo que no es adecuada para mi escenario)

  • Uso de AuthorizeAttribute y AuthorizationFilter (leí esta publicación https://stackoverflow.com/a/35863514/5426333 pero no pude cambiarlo correctamente)

  • Uso de middleware personalizado (¿cómo obtener AuthorizeAttribute de la acción actual?)

  • Uso de ActionFilter (¿es correcto por motivos de seguridad?)

No pude decidir cuál es la mejor opción para mi escenario y cómo implementarlo.

Primera pregunta : ¿La implementación de MVC5 es una mala práctica?

Segunda pregunta : ¿Tiene alguna sugerencia para implementar aspnet core?


Según los comentarios, aquí hay un ejemplo sobre cómo usar la autorización basada en políticas:

public class PermissionRequirement : IAuthorizationRequirement { public PermissionRequirement(PermissionEnum permission) { Permission = permission; } public PermissionEnum Permission { get; } } public class PermissionHandler : AuthorizationHandler<PermissionRequirement> { private readonly IUserPermissionsRepository permissionRepository; public PermissionHandler(IUserPermissionsRepository permissionRepository) { if(permissionRepository == null) throw new ArgumentNullException(nameof(permissionRepository)); this.permissionRepository = permissionRepository; } protected override void Handle(AuthorizationContext context, PermissionRequirement requirement) { if(context.User == null) { // no user authorizedd. Alternatively call context.Fail() to ensure a failure // as another handler for this requirement may succeed return null; } bool hasPermission = permissionRepository.CheckPermissionForUser(context.User, requirement.Permission); if (hasPermission) { context.Succeed(requirement); } } }

Y regístralo en tu clase de Startup :

services.AddAuthorization(options => { UserDbContext context = ...; foreach(var permission in context.Permissions) { // assuming .Permission is enum options.AddPolicy(permission.Permission.ToString(), policy => policy.Requirements.Add(new PermissionRequirement(permission.Permission))); } }); // Register it as scope, because it uses Repository that probably uses dbcontext services.AddScope<IAuthorizationHandler, PermissionHandler>();

Y finalmente en el controlador

[HttpGet] [Authorize(Policy = PermissionEnum.PERSON_LIST.ToString())] public ActionResult Index(PersonListQuery query) { ... }

La ventaja de esta solución es que también puede tener múltiples controladores para un requisito, es decir, si el primero tiene éxito, el segundo controlador puede determinar que es un error y puede usarlo con autorización basada en recursos con poco esfuerzo adicional.

El enfoque basado en políticas es la forma preferida de hacerlo por el equipo de ASP.NET Core.

De blowdart :

No queremos que escriba atributos de autorización personalizados. Si necesita hacer eso, hemos hecho algo mal. En su lugar, debe escribir los requisitos de autorización.


Tenía el mismo requisito y lo hice como se muestra a continuación y funciona bien para mí. Estoy usando .Net Core 2.0 Webapi

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class CheckAccessAttribute : AuthorizeAttribute, IAuthorizationFilter { private string[] _permission; public CheckAccessAttribute(params string[] permission) { _permission = permission; } public void OnAuthorization(AuthorizationFilterContext context) { var user = context.HttpContext.User; if (!user.Identity.IsAuthenticated) { return; } IRepository service = (IRepositoryWrapper)context.HttpContext.RequestServices.GetService(typeof(IRepository)); var success = service.CheckAccess(userName, _permission.ToList()); if (!success) { context.Result = JsonFormatter.GetErrorJsonObject(CommonResource.error_unauthorized, StatusCodeEnum.Forbidden); return; } return; } }

En el controlador, úsalo como a continuación

[HttpPost] [CheckAccess(Permission.CreateGroup)] public JsonResult POST([FromBody]Group group) { // your code api code here. }