9

I am attempting to inject SignInManager<ApplicationUser> and AspNetUserManager<ApplicationUser> into my Refresh Token middleware for my WebApi. Just to not I am using Identity, so the my ApplicationUser class is

public class ApplicationUser : IdentityUser<int>, IEntity

In my Middleware constructor I have;

private readonly AuthService _service;

public TokenProviderMiddleware(
    RequestDelegate next, 
    Func<IMyDataContext> context,
    SignInManager<ApplicationUser> signInManager,
    AspNetUserManager<ApplicationUser> userManager)
{
    _next = next;

    _serializerSettings = new JsonSerializerSettings
    {
        Formatting = Formatting.Indented
    };

    _service = new AuthService(context, signInManager, userManager);
}

An in my Startup.cs I have the following;

public void ConfigureServices(IServiceCollection services)
{
        services.AddDbContext<MyDataContext>(
            options => options.UseSqlServer(DbGlobals.DevDatabase));

        services.AddTransient<IMyDataContext, MyDataContext>();
        services.AddTransient<Func<IMyDataContext>>(provider => () => provider.GetService<IMyDataContext>());

        services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddEntityFrameworkStores<BemfeitoDataContext>()
        .AddDefaultTokenProviders();

        services.Configure<IdentityOptions>(options =>
        {
            // Password settings
            options.Password.RequireDigit = true;
            options.Password.RequiredLength = 8;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = true;
            options.Password.RequireLowercase = false;
            options.Password.RequiredUniqueChars = 6;

            // Lockout settings
            options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
            options.Lockout.MaxFailedAccessAttempts = 10;
            options.Lockout.AllowedForNewUsers = true;

            // User settings
            options.User.RequireUniqueEmail = true;
        });

        // Configure JwtIssuerOptions
        services.Configure<JwtIssuerOptions>(options =>
        {
            options.Issuer = JwtSettings.Issuer;
            options.Audience = JwtSettings.Audience;
            options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
        });

        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = JwtSettings.Issuer,

            ValidateAudience = true,
            ValidAudience = JwtSettings.Audience,

            ValidateIssuerSigningKey = true,
            IssuerSigningKey = _signingKey,

            RequireExpirationTime = false,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero
        };

        services.AddAuthentication(options =>
        {
             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
         })
         .AddJwtBearer(configureOptions =>
         {
             configureOptions.ClaimsIssuer = JwtSettings.Issuer;
             configureOptions.TokenValidationParameters = tokenValidationParameters;
             configureOptions.SaveToken = true;
             configureOptions.Events = new JwtBearerEvents
             {
                 OnAuthenticationFailed = context =>
                 {
                     Console.WriteLine("OnAuthenticationFailed: " +
                        context.Exception.Message);
                        return Task.CompletedTask;
                 },
                 OnTokenValidated = context =>
                 {
                     Console.WriteLine("OnTokenValidated: " +
                        context.SecurityToken);
                        return Task.CompletedTask;
                 }
            };
        });

            // api user claim policy
            services.AddAuthorization(options =>
            {
                options.AddPolicy("ApiUser", policy => policy.RequireClaim(JwtClaimIdentifiers.Rol, JwtClaims.ApiAccess));
            });

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpErrorHandlerMiddleware();

            app.UseTokenProviderMiddleware();
            app.UseRefreshTokenProviderMiddleware();
            app.UseAuthentication();

            app.UseMvc();

        }

When I run this I receive the following error;

InvalidOperationException: Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.SignInManager`1[ApplicationUser]' from root provider.

I have tried adding the following Transients;

        services.AddTransient<IUserStore<ApplicationUser>, UserStore<ApplicationUser, ApplicationRole, MyDataContext, int>>();
        services.AddTransient<SignInManager<ApplicationUser>>();
        services.AddTransient<UserManager<ApplicationUser>>();

But I seem to be going down a rabbit hole of injecting dependencies as it is now requesting UserStore be injected as well? Is there an easier way I missing to inject these services?

7
  • You don't get to choose if the UserManager<ApplicationUser> and SignInManager<ApplicationUser> are registered with a different lifetime. It happens automatically as part of the AddIdentity call in the Startup.cs The controller also has the usermanager as AspNetUserManager<ApplicationUser>. Did you mean to write UserManager<ApplicationUser>? Commented Mar 19, 2018 at 9:59
  • OK, so how do I gain access to them in the middle please? And yes, sorry a Typo, I meant UserManager<ApplicationUser> Commented Mar 19, 2018 at 9:59
  • Your Middleware should have an Invoke method with this signature public async Task Invoke(HttpContext context). You can use the RequestServices.GetService of the HttpContext to get a service from IoC. Commented Mar 19, 2018 at 10:27
  • I did see this as a way of access, as you can see I pass this over to my factory i.e. AuthService(context, signInManager, userManager) so I suppose I owul dhave to set the context in the constructore as its injected and create the instance in the Invoke method. Commented Mar 19, 2018 at 10:41
  • 1
    hey @MatthewFlynn did you find any solutions to this problem? I also wanted to user UserManager in a middleware, but can't inject it Commented Aug 21, 2019 at 2:05

1 Answer 1

7

There may be an easier way for you to access these services inside your middleware. Consider the following approach, instead of trying to inject the SignInManager signInManager and AspNetUserManager userManager into your middleware directly, inject an Microsoft.AspNetCore.Http.IHttpContextAccessor _httpContextAccessor

Then you can use the _httpContextAccessor to access the signInManager and userManager services like so:

var userManager = _httpContextAccessor.HttpContext.RequestServices.GetService<AspNetUserManager<ApplicationUser>>();
var signInManager = _httpContextAccessor.HttpContext.RequestServices.GetService<SignInManager<ApplicationUser>>();

Also make sure your middleware class has the following using statement: using Microsoft.Extensions.DependencyInjection;

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.