dotnet core 3.0 WebApi, applicationPart and authorization - c#

We have a modular application, which means that our api controllers get loaded during startup. We load the controllers into the applicationPart like this:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.ConfigureApplicationPartManager(applicationPartManager =>
{
foreach (var module in _modules)
{
var apiControllerAssemblies = module.GetApiControllerAssemblies();
foreach (var apiControllerAssembly in apiControllerAssemblies)
applicationPartManager.ApplicationParts.Add(new AssemblyPart(apiControllerAssembly));
}
});
We want to protect our apis with Basic authentication. I've created a middleware like this:
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization
Header");
//More to come
}
}
The middleware is registered in startup.cs like this:
services.AddAuthentication("Basic")
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("Basic", null);
Accessing localhost: will always trigger the HandleAuthenticateAsync method. However when I try to access the localhost:/user/users endpoint the method never hit the breakpoint and will always result in a HTTP 401 Unauthorized. The controller itself is marked with the Authorize attribute.
Any ideas where it goes wrong? Any hints to where I should start looking for a solution?
Thanks!

Not sure if this helps, but when I had to implement Authentication this is what I did.
a. Declare a class extending AuthenticationSchemeOptions
public class CustomAuthOptions: AuthenticationSchemeOptions
{
}
b. Declare a class implementing the AuthenticationHandler<TOptions>
internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
IHttpContextAccessor _httpContextAccessor;
IUser _user;
public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
IHttpContextAccessor httpContextAccessor, IUser user) : base(options, logger, encoder, clock)
{
_httpContextAccessor = httpContextAccessor;
_user = user;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
//logic to authenticate
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
//more code
}
}
c. Add an extension method to the AuthenticationBuilder class
public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder,
Action<CustomAuthOptions> config)
{
return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("CheckInDB", "CheckInDB", config);
}
d. Finally in the Startup.cs
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "CheckInDB";
options.DefaultChallengeScheme = "CheckInDB";
}).AddCustomAuth(c => { });
This may be more than what is needed, but when I was in the same boat, a couple of months ago, I spent a good few days piecing all of this together.

Related

OAuthHandler.Options property is null?

defined an oauth handler like so which works just fine.
public class MyHandler : OAuthHandler<MyOptions> {
public MyHandler(IOptionsMonitor<MyOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock) { }
// overriden CreateTicketAsync and BuildChallengeUrl protected methods.
}
but the authenticator requires that user can revoke authorization which doesn't seem to be supported by oauth in a native fashion. so in the handler, I added a specialization which is to revoke authorization like so.
public class MyHandler : OAuthHandler<MyOptions> {
public async Task RevokeAuthorizationAsync(string token) {
if(token == null) throw new ArgumentNullException(nameof(token));
// below, Options throws a NullReferenceException???
var request = new HttpRequestMessage(HttpMethod.Post, Options.RevocationEndpoint);
// other relevant code here...
}
}
so when the user hits the revoke button from the app, the account controller revoke method is called.
public class AccountController : Controller {
[Authorize]
public async Task Revoke()
=> HttpContext.RevokeAuthorizationAsync("refreshTokenObtainedByWhateverMean");
}
// which in turn calls upon the HttpContext extension written expressly for the purpose
public static class MyHttpContextExtensions {
public static async Task RevokeAuthorizationAsync(this HttpContext context, string accessOrRefreshToken) {
var handler=context.RequestServices.GetRequiredService<MyHandler>();
await handler.RevokeAuthorizationAsync(accessOrRefreshToken);
}
}
upon the call to MyHandler.RevokeAuthorizationAsync, the OAuthHandler.Options is null? how can that be? when authenticating and authorizing from within the MyHandler.CreateTicketAsync and MyHandler.BuildChallengeUrl, the OAuthHandler.Options property is set.
I suspect that I might not instantiate the MyHandler class properly using the HttpContext.RequestServices.GetRequiredService method. but if this is not it, how could I specialize MyHandler and provide OAuthHandler.Options ? because I need the Options.ClientId and Options.ClientSecret to revoke the authorization. both are configured like so from the program class.
public class Program {
builder.Services
.AddAuthentication(o => {
// some config here
})
.AddCookie()
.AddMyAuthenticator(o => {
o.ClientId=Configuration["ClientId"];
o.ClientSecret=Configuration["ClientSecret"];
});
}
so how is that OAuthHandler.Options is instantiated within the MyHandler.CreateTicketAsync and MyHandler.BuildChallengeUrl, and is null when I call upon the MyHandler.RevokeAuthorizationAsync method?

Custom AuthenticationHandler is called when a method has [AllowAnonymous]

I am trying to have my own custom authentication for my server. But it is called for every endpoint even if it has the [AllowAnonymous] attribute on the method. With my current code, I can hit my breakpoint in the HandleAuthenticateAsync method everytime, even on the allow anonymous functions.
The AddCustomAuthentication adds the authenticationhandler correctly
public void ConfigureServices(IServiceCollection services)
{
//services.AddAuthorization();
services.AddAuthentication(options =>
{
// the scheme name has to match the value we're going to use in AuthenticationBuilder.AddScheme(...)
options.DefaultAuthenticateScheme = "scheme";
options.DefaultChallengeScheme = "scheme";
})
.AddCustomAuthentication(o => { });
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
...
public class CustomAuthenticationHandler : AuthenticationHandler<CustomAuthenticationOptions>
{
public RvxAuthenticationHandler(
IOptionsMonitor<RvxAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var token = Request.Headers["token"].ToString();
if (string.IsNullOrWhiteSpace(token))
{
return AuthenticateResult.Fail("Invalid Credentials");
}
return AuthenticateResult.Success(new AuthenticationTicket(new System.Security.Claims.ClaimsPrincipal(), "Hi"));
}
Add this to the top of your HandleAuthenticateAsync method
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var endpoint = Context.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return Task.FromResult(AuthenticateResult.NoResult());
}
....
}
This is what Microsoft use under the covers in the AuthorizeFiler - https://github.com/dotnet/aspnetcore/blob/bd65275148abc9b07a3b59797a88d485341152bf/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.cs#L236
It will allow you to use the AllowAnonymous attribute in controllers to bypass your custom AuthenticationHandler.
This is how it is designed to work.
Authentication step is executed for every incoming call by the ASP.Net middleware added by your app.UseAuthentication() call. The step only sets up an instance of IPrincipal to the request.
If authentication succeeds, the request gets the IPrincipal that you pass to the AuthenticationTicket.
If it fails, the request gets an unauthenticated IIdentity in its IPrincipal (principal.Identity.IsAuthenticated will be false)
Then the request will still be passed to the next middleware and eventually to your endpoint method.
It's the AuthorizeAttribute that will prevent the request from reaching protected methods, not any AuthenticationHandler<T>.
I guess Your problem is different, After exiting from the
HandleAuthenticateAsync method it can not find the endpoint:
because the address is not correct
or it goes in error before exiting the HandleAuthenticateAsync method.
(For example on Request.Headers["Authorization"] as the header "Authorization" does not exists : fires an Exception.).
Recommendation:
Use Shlager UI to test the Api first.

Best Practice for Unit Testing a Controller that depends on UserManager<TUser>?

I have a controller with the following signature:
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private ILogger<UsersController> _logger;
private readonly UserManager<IdentityUser> _usermanager;
public UsersController(ILogger<UsersController> logger, UserManager<IdentityUser> usermanager)
{
_usermanager = usermanager;
_logger = logger;
}
[HttpGet("{_uniqueid}")]
public async Task<ObjectResult> GetUser(string _uniqueid)
{
//Retrieve the object
try
{
var user = await _usermanager.FindByIdAsync(uniqueid);
var model = JsonConvert.DeserializeObject<GetUserModel>(user.ToString());
return new ObjectResult(JsonConvert.SerializeObject(model));
}
catch(CustomIdentityNotFoundException e)
{
return new BadRequestObjectResult(("User not found: {0}", e.Message));
}
}
}
Right now my unit test looks like this:
public class UsersUnitTests
{
public UsersController _usersController;
private UserManager<IdentityUser> _userManager;
public UsersUnitTests()
{
_userManager = new MoqUserManager<IdentityUser>();
_usersController = new UsersController((new Mock<ILogger<UsersController>>()).Object, _userManager);
}
[Fact]
public async Task GetUser_ReturnsOkObjectResult_WhenModelStateIsValid()
{
//Setup
//Test
ObjectResult response = await _usersController.GetUser("realuser");
//Assert
//Should receive 200 and user data content body
response.StatusCode.Should().Be((int)System.Net.HttpStatusCode.OK);
response.Value.Should().NotBeNull();
}
}
and the Moq'd classes:
public class MoqUserManager<T> : UserManager<IdentityUser>
{
public MoqUserManager(IUserStore<IdentityUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<IdentityUser> passwordHasher, IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<IdentityUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
}
public MoqUserManager()
: base((new MoqUserStore().Store), new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<IdentityUser>>().Object, new Mock<IEnumerable<IUserValidator<IdentityUser>>>().Object,
new Mock<IEnumerable<IPasswordValidator<IdentityUser>>>().Object, new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object, new Mock<IServiceProvider>().Object, new Mock<ILogger<UserManager<IdentityUser>>>().Object)
{
}
}
public class MoqUserStore : IdentityUserStore
{
private Mock<IdentityUserStore> _store;
public MoqUserStore()
:base(new Mock<IdentityDbContext>().Object, new Mock<ILogger<IdentityUserStore>>().Object, null)
{
_store = new Mock<IdentityUserStore>(new Mock<IdentityDbContext>().Object, new Mock<ILogger<IdentityUserStore>>().Object, null);
_store.Setup(x => x.FindByIdAsync("realuser", default(CancellationToken))).Returns(Task.Run(() => new IdentityUser("realuser")));
_store.Setup(x => x.FindByIdAsync("notrealuser", default(CancellationToken))).Throws(new CustomIdentityNotFoundException());
_store.Setup(x => x.CreateAsync(new IdentityUser("realuser"), default(CancellationToken))).Returns(Task.Run(() => IdentityResult.Success));
}
public IdentityUserStore Store { get => _store.Object; }
}
I get reference not set to an instance of an object errors when the MoqUserManager constructor is called.
My question is: What is the best practice (I will settle for works but stinks to high heaven) for unit testing these types of controllers that depend on UserManager and/or SignInManager, and what is a easily repeatable way to mock the UserStore dependency?
I thought about the DI model and the dependencies of my controller. I only needed a handful of methods from UserManager, so I theorized about removing the dependency on UserManager from UsersController, and replacing it with some interface that implements the same signatures I needed from UserManager. Lets call that interface IMYUserManager:
public interface IMYUserManager
{
Task<IdentityUser> FindByIdAsync(string uniqueid);
Task<IdentityResult> CreateAsync(IdentityUser IdentityUser);
Task<IdentityResult> UpdateAsync(IdentityUser IdentityUser);
Task<IdentityResult> DeleteAsync(IdentityUser result);
}
Next, I needed to create a class that both is derived from UserManager and also implements IMYUserManager. The idea here is that implementing the methods from the interface will simply become overrides for the derived class, that way I get around FindByIdAsync (and the rest) being flagged as extension methods and requiring wrapping in a static class. Here is MyUserManager:
public class MYUserManager : UserManager<IdentityUser>, IMYUserManager
{
public MYUserManager(IUserStore<IdentityUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<IdentityUser> passwordHasher, IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<IdentityUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
}
public override Task<IdentityUser> FindByIdAsync(string userId)
{
return base.FindByIdAsync(userId);
}
//Removed other overridden methods for brevity; They also call the base class method
}
Almost home. Next, I naturally updated UsersController to use the IMYUserManager interface:
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private ILogger<UsersController> _logger;
private readonly IMYUserManager _usermanager;
public UsersController(ILogger<UsersController> logger, IMYUserManager
usermanager)
{
_usermanager = usermanager;
_logger = logger;
}
}
And, naturally after that I have to make this dependency available to the service container for all who desire to feast upon:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMYUserManager, MYUserManager>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
And, finally, after verifying that actually builds, I updated the test class:
public class UsersControllerTests
{
public UsersController _usersController;
private Mock<IMYUserManager> _userManager;
public UsersControllerTests()
{
_userManager = new Mock<IMYUserManager>();
_usersController = new UsersController((new Mock<ILogger<UsersController>>
()).Object, _userManager.Object);
}
[Fact]
public async Task GetUser_ReturnsOkObjectResult_WhenModelStateIsValid()
{
//Setup
_userManager.Setup(x => x.FindByIdAsync("realuser"))
.Returns(Task.Run(() => new IdentityUser("realuser","realuser1")));
_usersController.ModelState.Clear();
//Test
ObjectResult response = await _usersController.GetUser("realuser");
//Assert
//Should receive 200 and user data content body
response.StatusCode.Should().Be((int)System.Net.HttpStatusCode.OK);
response.Value.Should().NotBeNull();
}
}
What makes this a good solution?
Several things:
Removing the dependency on UserManager from UsersController was inline with the DI model. Abstracting away the dependencies (therefore abstracting away implementation details like extension methods) and making them available not only to be mocked, but available to the entire IServiceCollection means that I only have 3 very simple steps when I need to implement another method for the user manager:
Add the method signature to IMYUserManager
Override the method and call the base class implementation in MYUserManager
Mock new dependency inside of unit tests
I may revisit the scope of the service, I chose AddScoped() just to prove the concept, but performance and business requirements will choose whether or not that stays the same.

C# Dependency Injection - Authentication

I am trying to figure out .net core dependency injection. My project is currently a web api, with some custom authentication. I've added my authentication like so (in Startups.cs under "ConfigureServices":
services.AddAuthentication(Authentication.Hmac.HmacDefaults.AuthenticationScheme).AddHmac(options =>
{
options.AuthName = "myname";
options.CipherStrength = HmacCipherStrength.Hmac256;
options.EnableNonce = true;
options.RequestTimeLimit = 5;
options.PrivateKey = "myprivatekey";
});
My question is this: How do you access IMemoryCache within the authentication service? I've tried just created a new MemoryCache and passing it in, but that doesn't work. The main goal is for checking Nonce values (see if they are in the cache, if yes auth fails, if no, add to cache auth passes).
Again, this is .NET Core 2 (Web API).
UPDATES:
Here is the basis of the HmacHandler class (the part that ACTUALLY does the auth):
public class HmacHandler : AuthenticationHandler<HmacOptions>
{
private static string Signature;
private static string Nonce;
private static Encoding Encoder { get { return Encoding.UTF8; } set { } }
IMemoryCache MemoryCache { get; set; }
public HmacHandler(IOptionsMonitor<HmacOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{...}
}
Then there is the "Options" class.
public class HmacOptions : AuthenticationSchemeOptions
{...}
It can't have a constructor that takes parameters. I need to USE the IMemoryCache in the HmacHandler class. I tried adding IMemoryCache to it (in the constructor, etc). That did NOT work.
You would need to set IMemoryCache MemoryCache { get; set; } to public if you would like to use outside of the class via dependency injection.
public IMemoryCache MemoryCache { get; set; }
So the answer ended up being a combination of things here. So here is what I did:
Add the "public" to the IMemoryCache in the HmacHandler
Added the IMemoryCache to the constructor of HmacHandler
Changed the get/set of the cache from "TryGetValue/CreateEntry" to pure "Get/Set".
private IMemoryCache memoryCache { get; set; }
public HmacAuthenticationHandler(IOptionsMonitor<HmacAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IMemoryCache memCache)
: base(options, logger, encoder, clock)
{
memoryCache = memCache;
}
And then in HandleAuthenticateAsync use Get and Set of memoryCache.
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddAuthentication(Authentication.Hmac.HmacDefaults.AuthenticationScheme).AddHmac(options =>
{
options.AuthName = "myname";
options.CipherStrength = HmacCipherStrength.Hmac256;
options.EnableNonce = true;
options.RequestTimeLimit = 5;
options.PrivateKey = "myprivatekey";
// do your stuff with Test class here
});
}
public class Test {
private IMemoryCache _cache;
public Test(IMemoryCache cache) {
_cache = cache;
}
}

How to register custom UserStore & UserManager in DI

Here is my setup:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class ApplicationRole : IdentityRole<Guid>
{
}
public class ApplicationUserLogin : IdentityUserLogin<Guid>
{
}
public class ApplicationUserClaim : IdentityUserClaim<Guid>
{
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid>
{
}
Here is the definition of my UserStore
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, MyContext, Guid>
{
public ApplicationUserStore(MyContext context, IdentityErrorDescriber describer = null)
: base(context, describer)
{
}
}
Here is the definition of my UserManager
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IEnumerable<IUserTokenProvider<ApplicationUser>> tokenProviders,
ILoggerFactory logger, IHttpContextAccessor contextAccessor)
: base(
store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
tokenProviders, logger, contextAccessor)
{
}
}
Here is the definition of my DbContext:
public class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
And here is my Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.Get("Data:DbConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<MyContext, Guid>()
.AddUserStore<ApplicationUserStore>()
.AddRoleStore<ApplicationRoleStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleManager<ApplicationRoleManager>()
.AddDefaultTokenProviders();
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
The dependency of this constructor will work:
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
This one won't:
public AccountController(ApplicationUserManager userManager, SignInManager<ApplicationUser> signInManager)
Anyone has an idea on what I'm doing wrong?
DI in general is intended for interface-driven development; .AddUserManager<ApplicationUserManager>() specifies an implementation UserManager<>, not the service interface. That means that it's still expecting you to get UserManager<ApplicationUser> and only use it that way; it'll give you an ApplicationUserManager.
I'm assuming that you have additional methods you want to use on your ApplicationUserManager. If not, just use the dependency constructor the way it works and enjoy the interface-driven development. If so, you have 3 options:
Use extension via composition rather than inheritance. Rather than inheriting from UserManager<>, write ApplicationUserManager as a wrapper class; you can include it in the constructor. This should give you all the functionality you need inside of the ApplicationUserManager.
Add it as-is to the DI framework yourself. This isn't as difficult as it sounds, since the UserManager<> has no real state itself:
services.AddScoped<ApplicationUserManager>();
The disadvantage here is that you'll actually have two UserManager<> objects for the user's scope; there could be some inefficiencies as a result. From the state of the current code, I don't think it is.
Write it as extension methods. If you have a number of dependencies and not just the UserManager<>'s base functionality, this could be really complex.
I am now on ASP.NET Core 1.1 and this behavior has been fixed.
I can easily implement my own UserManager and UserStore, then bootstrap the app as following:
// identity models
services
.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddUserManager<ApplicationUserManager>()
.AddUserStore<ApplicationUserStore>()
.AddDefaultTokenProviders();
and inject both UserManager and UserStore into my Controller, without any problem:
public AccountController(
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IHttpContextAccessor httpContextAccessor,
ApplicationUserManager userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_interaction = interaction;
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_account = new AccountService(_interaction, httpContextAccessor, clientStore);
}
I came up with this:
// Extract IApplicationUserManager interface with all methods you are using
public class ApplicationUserManager : UserManager<ApplicationUser>, IApplicationUserManager
// Register your custom user manager
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddUserManager<ApplicationUserManager>();
// Return same scoped instance whenever you injecting your custom user manager into any constructor
services.AddScoped<IApplicationUserManager>(s => s.GetService<ApplicationUserManager>());

Categories