Steven B.
Steven B.

Reputation: 9362

Service Authorization with Dependency Injection in Web API 2

I have an n-tiered web api 2 project that is structured as such:

  1. Web Layer
  2. Service/Business Layer
  3. Data/Repository Layer

The web controllers have the corresponding service injected with Autofac and each service has the corresponding repository injected. This works fine.

Now, I am needing to inject an object that has some information about the user for business logic purposes. Similar to this:

public class OrderService : IOrderService
{
    private readonly IOrderRepo _Repo;
    private readonly EnterpriseUser _EnterpriseUser;

    public OrderService(IOrderRepo repo, EnterpriseUser enterpriseUser)
    {
        this._Repo = repo;
        this._EnterpriseUser = enterpriseUser;
    }
    ....
}

The user information is needed for things such as if they are a certain privilege level then their orders may be placed in a queue to be reviewed by an administrator or they may receive a discount.

My issue arises with the Authentication process. The EnterpriseUser requires a claim from the current IIdentity.

builder.Register(ctx =>
{
    // Identity extension to retrieve claim from User
    var userLinkCode = ctx.Resolve<HttpContextBase>().User.Identity.GetUserLinkCode();
    // Retrieves a header from the request
    var partnerLinkCode = ctx.Resolve<ConnectionInfo>().PartnerLinkCode;
    return EnterpriseUser.Create(userLinkCode, partnerLinkCode);
})
.As<EnterpriseUser>()
.InstancePerRequest();

So when the user's token has expired, Autofac will throw the following exception

A delegate registered to create instances of 'LVV.Services.EnterpriseUser' returned null

because the Claims are empty and the AuthorizeAttribute is never able to reject the call with 401 Unauthorized since the controller's constructor runs before the AuthorizeAttribute.

Is there known work around for this?

Possibly a way to reject the call with 401 if the delegate returns null?

Or a better way to inject information about the user to the service layer, while still allowing for the OAuth authentication process to function.

Upvotes: 3

Views: 857

Answers (1)

KozhevnikovDmitry
KozhevnikovDmitry

Reputation: 1720

I suggest to implement NullObject pattern here to let AuthorizeAttribute do its job and not confuse Autofac and contructors with raw null values. I don't see your entire code, so the example below is just an illustration of the idea. Let's say that we extend EnterpriseUser in this way:

public class EnterpriseUser
{
    /// <summary>
    /// Always true for real user
    /// </summary>
    public virtual bool IsAuthentificated => true;

    public static EnterpriseUser Create(string userLinkCode, string partnerLinkCode)
    {
        if (string.IsNullOrEmpty(userLinkCode) ||
            string.IsNullOrEmpty(partnerLinkCode))
        {
            return new DummyEnterpriseUser();
        }

        // create true user here with usin link codes
        return new EnterpriseUser(userLinkCode, partnerLinkCode);
    }

    // Some usefull code here
}


/// <summary>
/// NullObject implementation for <see cref="EnterpriseUser"/>
/// </summary>
public class DummyEnterpriseUser : EnterpriseUser
{
    /// <summary>
    /// Always false for dummy user
    /// </summary>
    public override bool IsAuthentificated => false;

    public DummyEnterpriseUser()
    {

    }
} 

IsAuthentificated flag was added just in case, you probably wouldn't need it. I also assumed that your extension method GetUserLinkCode returns null in case of empty claims. The final implementation will depend of your code of course.

Upvotes: 3

Related Questions