Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add the UserManager via Dependency Injection in AspNet.Core 2.1?

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
{
    ...
}
like image 269
littleowlnest Avatar asked Nov 07 '22 04:11

littleowlnest


People also ask

How can we inject the dependency into the 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.

What is dependency injection in .NET Core MVC?

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.


1 Answers

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.

like image 108
jerbersoft Avatar answered Nov 16 '22 23:11

jerbersoft