I've created an Asp.Net Core 2.1 Web Api that uses Bearer Token authentication using Identity Server 4. I have two db contexts, one that is for identity and one that is my data access for my custom application. I want to be able to use the UserManager and UserStore in my Web Api using dependency injection in my controllers.
The problem is that once I add in the "relevant" code for DI, my controller methods are throwing a 302 and trying to redirect me to a login URL. It's like my bearer authentication is being overridden. Below is what my Startup.cs looks like. Any thoughts on how this should be done?
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<CustomContext>(options =>
options.UseSqlServer(connectionString));
// start of the stuff that should add the usermanager and userstore
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// end of the stuff
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://authenticate.com";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
services.AddCors(options =>
{
// this defines a CORS policy called "default"
options.AddPolicy("default", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseCors("default");
app.UseMvc();
}
The controllers look like this:
public class PlayerController : BaseApiController
{
private readonly UserManager<ApplicationUser> userManager;
public PlayerController(UserManager<ApplicationUser> _userManager)
{
userManager = _userManager;
}
.....
}
With BaseApiController like this:
[Route("api/[controller]")]
[Authorize]
public class BaseApiController : Controller
{
...
}
ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container. The built-in container is represented by IServiceProvider implementation that supports constructor injection by default.
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
services.AddIdentity<TUser>()
adds an "unnecessary" authentication configuration since you already have a bearer scheme from the services.AddAuthentication("Bearer").AddIdentityServerAuthentication()
configuration. Take a look at the code below for AddIdentity()
. Notice how many schemes were also added (including cookie scheme).
public static IdentityBuilder AddIdentity<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Services used by identity
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddCookie(IdentityConstants.ApplicationScheme, o =>
{
o.LoginPath = new PathString("/Account/Login");
o.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
})
.AddCookie(IdentityConstants.ExternalScheme, o =>
{
o.Cookie.Name = IdentityConstants.ExternalScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
})
.AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
o.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = SecurityStampValidator.ValidateAsync<ITwoFactorSecurityStampValidator>
};
})
.AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
});
// cut for brevity
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
You dont need that. What you do need is:
services.AddIdentityCore<TUser>()
which does not add another authentication configuration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With