Simple Injector将依赖注入自定义全局身份验证筛选器和OWIN中间件OAuthAuthorizationServerProvider

时间:2015-08-11 23:58:06

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

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

  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;我们知道我们可以使用begin execution context scope,但我们想要一个优雅的解决方案。

    using (Ioc.Container.BeginExecutionContextScope())
    {
    
    }
    
  3. 更新

    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;
            }
        }
    }
    

1 个答案:

答案 0 :(得分:3)

使用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<MyPassiveAttribute>实现中实现所需的逻辑。

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

// 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
    }
}