MVC安全过滤器传递接口

时间:2016-06-21 13:53:02

标签: c# asp.net asp.net-mvc

我有一个密封的课程:

 public sealed class AuthorizeLaoAttribute : AuthorizeAttribute

然后我通常会在MVC控制器中使用它:

 [HttpGet]
 [AuthorizeLaoAttribute]
 public ActionResult Overview(int id)

我想更进一步,因为我想在AuthorizeLaoAttributeClass中注入一个接口,这样我就可以在确定用户是否获得授权时执行一些复杂的逻辑。

所以我想在表单中包含一个构造函数:

 public AuthorizeLaoAttribute(IServiceUserService serviceUserService)

在密封班上。然而,在控制器中,它抱怨我传递的值必须是静态的,常量类型,类型或数组。我可以在使用它们的基础上传递interger值,然后通过声明' New'直接对照类。在我的密封类方法中,但它打破了我的DI模式。有没有办法做我想做的事。

所以,如果我这样做:

public AuthorizeLaoAttribute(int id)

然后

[AuthorizeLaoAttribute(12)]
public ActionResult Overview(int id)

没有抱怨,但我真的不想在我的安全类中实例化该对象。

2 个答案:

答案 0 :(得分:1)

您可以使用passive attribute执行此操作。这意味着属性类本身没有任何代码,因为,正如您所确定的,您不能将任何内容注入属性。

步骤如下:

  • 创建要放置在控制器或方法上的属性。
  • 创建IAuthorizationFilter。这是真正的工作所在。过滤器检查属性是否在被调用的控制器或方法上。如果是,则进行过滤。如果该属性不存在则无效。
  • 在应用程序启动时,从容器中解析过滤器的实例(这使您能够进行依赖项注入。)将该过滤器添加到全局过滤器集合中。因此,过滤器在技术上将针对每个请求执行。但是当它执行时,它将检查属性。因此它最终像“正常”授权属性一样工作。仅当属性存在时,过滤器才真正适用。

这种方法是由.NET的Dependency Injection的作者Mark Seemann开发的。我只是把它扔到那里因为它听起来有点复杂,但它来自一个很好的来源。

我使用它并且它有效。 Here's a blog post更详细地描述了它,并展示了如何通过为处理属性检查的过滤器创建基类来简化它。这样你就不必一遍又一遍地写这个部分。起初我认为整个概念有点沉重,但使用基类使它变得更加简单。现在,您需要编写的唯一部分是过滤器本身的实际逻辑。

博客文章中的示例涉及Web API,但它也适用于MVC过滤器。这是我用于MVC授权过滤器的基类。除了检查属性是否存在外,它还将属性本身传递给过滤器的行为,以防该属性具有过滤器需要检查的属性。

public abstract class AuthorizationFilterBehaviorBase<TAttribute> : IAuthorizationFilter where TAttribute : Attribute
{
    private readonly IContextAttributeInspector _attributeInspector;

    protected AuthorizationFilterBehaviorBase(IContextAttributeInspector attributeInspector)
    {
        _attributeInspector = attributeInspector;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        TAttribute attribute = null;
        if (_attributeInspector.TryGetActionAttribute(filterContext.ActionDescriptor, out attribute)
            || _attributeInspector.TryGetControllerAttribute(filterContext, out attribute))
        {
            OnAuthorizationBehavior(filterContext, attribute);
        }
    }

    protected abstract void OnAuthorizationBehavior(AuthorizationContext authorizationContext, TAttribute attribute);
}

查找属性的接口和类将分别分解以维护SRP。

public interface IContextAttributeInspector
{
    bool ControllerHasAttribute<TAttribute>(ControllerContext controllerContext) where TAttribute : Attribute;
    bool ActionHasAttribute<TAttribute>(ActionDescriptor actionDescriptor) where TAttribute : Attribute;
    bool TryGetControllerAttribute<TAttribute>(ControllerContext controllerContext, out TAttribute attribute) where TAttribute : Attribute;
    bool TryGetActionAttribute<TAttribute>(ActionDescriptor actionDescriptor, out TAttribute attribute) where TAttribute : Attribute;
}  

public class ContextAttributeInspector : IContextAttributeInspector
{
    public bool ControllerHasAttribute<TAttribute>(ControllerContext controllerContext) where TAttribute : Attribute
    {
        return controllerContext.Controller.GetType()
            .GetCustomAttributes(false)
            .Any(attribute => attribute.GetType().IsAssignableFrom(typeof(TAttribute)));
    }

    public bool ActionHasAttribute<TAttribute>(ActionDescriptor actionDescriptor) where TAttribute : Attribute
    {
        return actionDescriptor
            .GetCustomAttributes(typeof(TAttribute), true)
            .Any();
    }

    public bool TryGetControllerAttribute<TAttribute>(ControllerContext controllerContext, out TAttribute attribute) where TAttribute : Attribute
    {
        var foundAttribute = controllerContext.Controller.GetType()
            .GetCustomAttributes(false)
            .FirstOrDefault(customAttribute => customAttribute.GetType().IsAssignableFrom(typeof(TAttribute)));
        if (foundAttribute != null)
        {
            attribute = (TAttribute)foundAttribute;
            return true;
        }
        attribute = null;
        return false;
    }

    public bool TryGetActionAttribute<TAttribute>(ActionDescriptor actionDescriptor, out TAttribute attribute) where TAttribute : Attribute
    {
        var foundAttribute = actionDescriptor
            .GetCustomAttributes(typeof(TAttribute), true)
            .FirstOrDefault();
        if (foundAttribute != null)
        {
            attribute = (TAttribute)foundAttribute;
            return true;
        }
        attribute = null;
        return false;
    }
}

答案 1 :(得分:0)

使用DI

public sealed class AuthorizeLaoAttribute : AuthorizeAttribute
{
    [Dependency]
    private IServiceUserService serviceUserService{ get; set; }
}

使用Unity

public static class UnityConfig
{
    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterType<IServiceUserService , ServiceUserService>();
    }
}