Pregunta

Estoy trabajando en una seguridad basada en roles para nuestra aplicación y esencialmente quiero hacer MVC de Verison personalizados AuthorizeAttribute - Pero solo en la capa lógica de negocios, donde no nos vinculamos a MVC.

He mirado PrincipalPermissionAttribute Pero parece que no tiene una forma de personalizarlo, ya que está sellado. Solo quiero crear una versión personalizada en la que pueda verificar la membresía en ningún de una lista de roles sin utilizar múltiples atributos, y también definir dónde buscar la membresía de rol.

¿Hay algo como esto en .NET que me estoy perdiendo? ¿O alguien tiene una idea de cómo hacer esto sin reimplementar el AuthorizeAtTribute/Roleprovider/etc. de ASP.NET?

EDITAR

Actualmente tengo una versión imperativa en ejecución, pero prefiero tener una versión de atributo declarativo, ya que es más fácil verla por encima del método/clase.

En este momento tengo lo siguiente en una clase base abstracta para mi capa de negocios:

protected void EnsureEditorLevelAccess()
{
    var allowedRoles = new[]
                            {
                                Roles.Administrator,
                                Roles.Editor,
                            };

    var roles = GetAccountRoles(GetCurrentUsername());

    if (roles.Any(role => allowedRoles.Contains(role)))
    {
        return;
    }

    throw new SecurityException("You do not have sufficient privileges for this operation.");
}

Me gusta poder usar Roles.Administrator etc. Debido a que los nombres de roles son horribles (Grupo de Active Directory ...), por lo que estaba pensando en envolver esos detalles en el constructor de un atributo personalizado que puedo dejar caer en la parte superior de las clases/métodos.

GetAccountRoles es solo una fachada sobre una propiedad inyectable de proveedor de roles, que puedo configurar para usar AD o una versión de prueba que usa la base de datos.

Podría subclase Attribute, pero no estoy seguro de cómo comenzaría la verificación de seguridad.

¿Fue útil?

Solución

Puede crear un nuevo atributo que utilice el PRINCIPAL existente si eso sería suficiente para sus necesidades. Si su implementación imperativa existente utiliza PrincipalPermission, entonces este debería ser el caso. Sin embargo, si su versión imperativa hace algo más, es posible que deba considerar implementar un permiso personalizado y un atributo correspondiente. Si no está seguro de si esto es necesario, tal vez pueda compartir algunos detalles sobre su enfoque imperativo actual ...


Después de la actualización de la pregunta ...

En realidad, es posible usar "cualquier" lógica con PrincipalPermission, aunque requiere la unión de múltiples instancias, lo que no es particularmente práctico trabajar con un atributo. Esto hace que sea mucho más razonable crear un atributo personalizado, que podría parecerse a lo siguiente:

[Serializable]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class AnyRolePermissionAttribute : CodeAccessSecurityAttribute
{
    public AnyRolePermissionAttribute(SecurityAction action)
        : base(action)
    {
    }

    public string Roles { get; set; }

    public override IPermission CreatePermission()
    {
        IList<string> roles = (this.Roles ?? string.Empty).Split(',', ';')
                                .Select(s => s.Trim())
                                .Where(s => s.Length > 0)
                                .Distinct()
                                .ToList();

        IPermission result;
        if (roles.Count == 0)
        {
            result = new PrincipalPermission(null, null, true);
        }
        else
        {
            result = new PrincipalPermission(null, roles[0]);
            for (int i = 1; i < roles.Count; i++)
            {
                result = result.Union(new PrincipalPermission(null, roles[i]));
            }
        }

        return result;
    }
}

Desafortunadamente, no puede usar matrices en atributos de seguridad, por lo que la lista de roles debe representarse como una cadena. p.ej:

[AnyRolePermission(SecurityAction.Demand, Roles = "Foo, Bar")]

Puede usarlo con sus constantes a través de la concatenación de tiempo de diseño. p.ej:

[AnyRolePermission(SecurityAction.Demand, Roles = Roles.Administrator + ", " + Roles.Editor)]

En cuanto a su proveedor de roles personalizados, el lugar apropiado para usarlo está en el principal de subprocesos, no en el permiso o el atributo. Por ejemplo, si actualmente está utilizando un GenericPrincipal, podría reemplazarlo con un principal personalizado que utilice su proveedor de roles personalizado para recuperar los roles de la identidad objetivo.

Otros consejos

Puede derivar su propio CodeAccessSecurityAttribute e implementar su lógica en torno al hilo.

esencialmente, querrías verificar allowedRoles.Any(r => Thread.CurrentPrincipal.IsInRole(r))

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top