MVC安全过滤器通过接口



我有一个形式的密封类:

 public sealed class AuthorizeLaoAttribute : AuthorizeAttribute

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

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

我想更进一步,因为我想将界面注入授权,以便我可以在确定是否授权的情况下执行一些复杂的逻辑。

所以我想以形式包括一个构造函数:

 public AuthorizeLaoAttribute(IServiceUserService serviceUserService)

在密封班上。但是,在控制器中,它抱怨我所传递的值必须是静态,恒定类型,类型或数组。我可以在使用它们时以基于Interger值的形式传递Interger值,然后通过在密封的类方法中宣布"新"来直接对付类,但它会破坏我的DI模式。有没有办法做我想做的事。

所以如果我做类似:

的事情
public AuthorizeLaoAttribute(int id)

,然后

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

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

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

步骤是:

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

这种方法是由.NET依赖注入的作者Mark Seemann开发的。我只是把它扔到那里,因为它听起来可能有些令人费解,但它来自一个很好的来源。

我使用它,它可以工作。这是一篇博客文章,可以更详细地描述它,并通过为过滤器创建一个处理属性检查的过滤器来简化它。这样,您就不必一遍又一遍地写出那部分。起初,我认为整个概念有些沉重,但是使用基类使它变得更加简单。现在,您唯一需要写的部分是过滤器本身的实际逻辑。

博客文章中的示例涉及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;
    }
}

使用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>();
    }
}

最新更新