我有一个密封的课程:
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)
没有抱怨,但我真的不想在我的安全类中实例化该对象。
答案 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>();
}
}