Reputation: 9362
I have an n-tiered web api 2 project that is structured as such:
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
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