I have a controller where I am injecting a service interface into the constructor. The service has interfaces injected into its constructor as well. The IoC container (Unity) needs to use information about the user when constructing one of the classes that it returns for a given interface.
What is happening, is that the controller is being instantiated before the [Authorize] attribute is evaluated and the user is authenticated. This forces Unity to perform the dependency injection and use information about the user before they have logged in. None of this was a problem when we were using integrated windows authentication, but now we are using OpenID Connect to Azure AD and the user info isn't there until they log in (which happens AFTER the controller is instatiated).
I heard (in other posts) that there is a way to configure my owin startup class to move authentication earlier in the process, but I cannot find any examples on how to do this. I need the authentication to happen before the controller is instantiated.
Here is a simplified example of what I have...
Controller:
[Authorize]
public class MyController : Controller
{
private readonly IMyService myService;
public MyController(IMyService myService)
{
this.myService = myService;
}
// ...
}
Unity Configuration:
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
// ...
return container
.RegisterType<ISomeClass, SomeClass>()
.RegisterType<IMyService>(new InjectionFactory(c =>
{
// gather info about the user here
// e.g.
var currentUser = c.Resolve<IPrincipal>();
var staff = c.Resolve<IStaffRepository>().GetBySamAccountName(currentUser.Identity.Name);
return new MyService(staff);
}));
}
}
OWIN Startup (Startup.Auth.cs):
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = this.clientID,
Authority = this.authority,
PostLogoutRedirectUri = this.postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = context =>
{
context.ProtocolMessage.DomainHint = this.domainHint;
return Task.FromResult(0);
},
AuthorizationCodeReceived = context =>
{
var code = context.Code;
var credential = new ClientCredential(this.clientID, this.appKey.Key);
var userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var authContext = new AuthenticationContext(this.authority, new NaiveSessionCache(userObjectID));
var result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, this.graphUrl);
AzureAdGraphAuthenticationHelper.Token = result.AccessToken;
return Task.FromResult(0);
}
}
});
}