0

I used Simple Injector as our Ioc container; we have two problems.

  1. We want to inject into our custom authentication filter; we read the post of converting attribute to a passive attribute: Convert Attribute into a passive. But we can't convert custom authentication filter 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. We want to inject dependency into OWin middleware OAuthAuthorizationServerProvider; we know we can use begin execution context scope, but we want an elegant solution.

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

Updated

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;
        }
    }
}
Steven
  • 166,672
  • 24
  • 332
  • 435
yo2011
  • 971
  • 2
  • 12
  • 38
  • "But we can't convert custom authentication filter attribute into a passive.". Why? – Steven Aug 12 '15 at 05:52
  • Hello, Steven; I already read your post about passive attributes but in case of authentication filter;The attribute must implement IAuthenticationFilter and in your post you depend on OnActionExecuting method but in my case, the AuthenticateAsync and ChallengeAsync runs even before your ActionFilterDispatcher – yo2011 Aug 12 '15 at 09:45
  • In that case you can create a filter that is registered in the pipeline before all other filters. This filter can use its own IAutFilter. – Steven Aug 12 '15 at 12:44
  • Could you give me an example? – yo2011 Aug 12 '15 at 13:31
  • Hi Steven; I am waiting your feedback – yo2011 Aug 12 '15 at 14:27
  • Your question about your middlewhere issue is too vague. Please create a new question for this on Stackoverflow with more detailed information about what you you have, what you are trying to achieve and what you've tried. – Steven Aug 15 '15 at 10:34

1 Answers1

3

The equivalent code for working with IAuthenticationFilter is:

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

Registration is done as follows:

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

Now instead of making your attributes active, you can make the attribute passive and implement the required logic inside an IAuthenticationFilter<MyPassiveAttribute> implementation.

Your attribute and new component might look like this:

// 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
    }
}
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Hi Steven;Thanks for your help; i already update my code according to your advise but there is compile error as the attribute must have a parameter less(default constructor); please see the updates in the post and tell me how to solve it; Also, i want to solve the second issue(OWIN middle ware issue) – yo2011 Aug 13 '15 at 21:58
  • You are mixing things up. Passive attribute means: no behavior. You should split data and behavior. Your `IAuthenticationFilter` implementation should not inherit from `Attribute`. – Steven Aug 14 '15 at 15:05
  • @yo2011: See my update. I added the attribute and the component implementations as example. – Steven Aug 15 '15 at 10:32
  • Thanks Steven for your great help; I think the attribute RequiresBearerAuthenticationAttribute doesn't have any meaningful as i have no data to carry so , i don't need it; only i want to implement IAuthenticationFilter with the two methods and all of my logic will be on BearerAuthenticationFilter; Also, i want to fix the second issue (OWIN middleware code) – yo2011 Aug 16 '15 at 00:09
  • I fxied the second issue using var dependencyResolver = ServiceLocator.Current.GetInstance(); using (dependencyResolver.BeginScope()) {} – yo2011 Aug 24 '15 at 22:30