【问题标题】:Simple Injector inject dependency into custom global authentication filters and OWIN middle ware OAuthAuthorizationServerProviderSimple Injector 将依赖项注入自定义全局身份验证过滤器和 OWIN 中间件 OAuthAuthorizationServerProvider
【发布时间】:2015-11-04 09:30:05
【问题描述】:

我使用 Simple Injector 作为我们的 Ioc 容器;我们有两个问题。

  1. 我们想注入我们的自定义身份验证过滤器;我们阅读了将属性转换为被动属性的帖子:Convert Attribute into a passive。但我们无法将自定义身份验证过滤器属性转换为被动属性。

    public class BearerAuthentication : Attribute, IAuthenticationFilter
    {
       public async Task AuthenticateAsync(
           HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
    
        }
       public Task ChallengeAsync(
           HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
    
        }
    }
    
  2. 我们想将依赖注入 OWin 中间件 OAuthAuthorizationServerProvider;我们知道我们可以使用开始执行上下文范围,但我们想要一个优雅的解决方案。

    using (Ioc.Container.BeginExecutionContextScope())
    {
    
    }
    

更新

public interface IAuthenticationFilter<TAttribute> where TAttribute : Attribute
{
    Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken);
    Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
}
public  class BearerAuthenticationFilter : Attribute, IAuthenticationFilter<BearerAuthenticationFilter>
{
    private readonly IAuthenticationBusinessEngine _authenticationBusinessEngine;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public BearerAuthenticationFilter(IAuthenticationBusinessEngine authenticationBusinessEngine, IHttpContextAccessor httpContextAccessor)
    {
        _authenticationBusinessEngine = authenticationBusinessEngine;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {

         throw new NotImplementedException();  

        }
    }

    public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

}
public class AuthenticationFilterDispatcher : IAuthenticationFilter
{
    private readonly Func<Type, IEnumerable> _container;
    public AuthenticationFilterDispatcher(Func<Type, IEnumerable> container)
    {
        _container = container;
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        var descriptor = context.ActionContext.ActionDescriptor;
        var attributes = descriptor.ControllerDescriptor.GetCustomAttributes<Attribute>(true)
            .Concat(descriptor.GetCustomAttributes<Attribute>(true));

        foreach (var attribute in attributes)
        {
            var filterType = typeof(IAuthenticationFilter<>).MakeGenericType(attribute.GetType());
            var filters = _container.Invoke(filterType);

            foreach (dynamic actionFilter in filters)
            {
                await actionFilter.AuthenticateAsync(context, cancellationToken);
            }
        }
    }

    public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

    public bool AllowMultiple
    {
        get
        {
            return true;
        }
    }
}

【问题讨论】:

  • “但我们无法将自定义身份验证过滤器属性转换为被动属性。”。为什么?
  • 你好,史蒂文;我已经阅读了您关于被动属性的帖子,但在身份验证过滤器的情况下;该属性必须实现 IAuthenticationFilter 并且在您的帖子中您依赖于 OnActionExecuting 方法,但在我的情况下,AuthenticateAsync 和 ChallengeAsync 甚至在您的 ActionFilterDispatcher 之前运行
  • 在这种情况下,您可以在所有其他过滤器之前创建一个在管道中注册的过滤器。此过滤器可以使用自己的 IAutFilter.
  • 你能举个例子吗?
  • 嗨史蒂文;我正在等待您的反馈

标签: asp.net-web-api dependency-injection action-filter simple-injector .net-attributes


【解决方案1】:

使用IAuthenticationFilter 的等效代码是:

public interface IAuthenticationFilter<TAttribute> where TAttribute : Attribute
{
    Task AuthenticateAsync(TAttribute attribute, HttpAuthenticationContext context);
}

public class AuthenticationFilterDispatcher : IAuthenticationFilter
{
    private readonly Func<Type, IEnumerable> container;
    public AuthenticationFilterDispatcher(Func<Type, IEnumerable> container) {
        this.container = container;
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context,
        CancellationToken token) {
        var descriptor = context.ActionContext.ActionDescriptor;
        var attributes = descriptor.ControllerDescriptor
            .GetCustomAttributes<Attribute>(true)
            .Concat(descriptor.GetCustomAttributes<Attribute>(true));

        foreach (var attribute in attributes) {
            Type filterType = typeof(IAuthenticationFilter<>)
                .MakeGenericType(attribute.GetType());
            IEnumerable filters = this.container.Invoke(filterType);

            foreach (dynamic actionFilter in filters) {
                await actionFilter.AuthenticateAsync((dynamic)attribute, context);
            }
        }
    }

    public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, 
        CancellationToken token) { }

    public bool AllowMultiple { get { return true; } }
}

注册如下:

GlobalConfiguration.Configuration.Filters.Add(
    new AuthenticationFilterDispatcher(container.GetAllInstances));

// For Simple Injector 2.x:
container.RegisterManyForOpenGeneric(typeof(IAuthenticationFilter<>),
    container.RegisterAll, 
    new[] { typeof(IAuthenticationFilter<>).Assembly });

// For Simple Injector 3.x:
container.RegisterCollection(typeof(IAuthenticationFilter<>),
    new[] { typeof(IAuthenticationFilter<>).Assembly });

现在,您可以将属性设为被动,并在 IAuthenticationFilter&lt;MyPassiveAttribute&gt; 实现中实现所需的逻辑,而不是让您的属性处于活动状态。

您的属性和新组件可能如下所示:

// NOTE: This attribute does not derive from anything Web API specific,
// just from Attribute
public class RequiresBearerAuthenticationAttribute : Attribute
{
    // put here properties if required
}

public class BearerAuthenticationFilter 
    : IAuthenticationFilter<RequiresBearerAuthenticationAttribute>
{
    private readonly IAuthenticationBusinessEngine _authenticationBusinessEngine;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public BearerAuthenticationFilter(
        IAuthenticationBusinessEngine authenticationBusinessEngine, 
        IHttpContextAccessor httpContextAccessor)
    {
        _authenticationBusinessEngine = authenticationBusinessEngine;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task AuthenticateAsync(RequiresBearerAuthenticationAttribute attribute, 
        HttpAuthenticationContext context)
    {
        // TODO: Behavior here
    }
}

【讨论】:

  • 嗨史蒂文;感谢您的帮助;我已经根据您的建议更新了我的代码,但是由于属性必须有一个参数 less(默认构造函数),所以存在编译错误;请查看帖子中的更新并告诉我如何解决;另外,我想解决第二个问题(OWIN中间件问题)
  • 你把事情搞混了。被动属性意味着:没有行为。您应该拆分数据和行为。您的 IAuthenticationFilter&lt;T&gt; 实现不应继承自 Attribute
  • @yo2011:查看我的更新。我添加了属性和组件实现作为示例。
  • 感谢 Steven 的大力帮助;我认为 RequiresBearerAuthenticationAttribute 属性没有任何意义,因为我没有要携带的数据,所以我不需要它;只有我想用这两种方法实现 IAuthenticationFilter 并且我的所有逻辑都将在 BearerAuthenticationFilter 上;另外,我想解决第二个问题(OWIN 中间件代码)
  • 我使用 var dependencyResolver = ServiceLocator.Current.GetInstance(); 解决了第二个问题;使用 (dependencyResolver.BeginScope()) {}
猜你喜欢
  • 1970-01-01
  • 2016-09-01
  • 2017-06-18
  • 2015-04-02
  • 2013-07-14
  • 2016-07-03
  • 2014-01-30
  • 1970-01-01
  • 2015-01-01
相关资源
最近更新 更多