Due to a number of factors on the project I am required to create an instance of UserManager
manually, without the use of DI. I am doing so as follows:
var userstore = new UserStore<ApplicationUser>(_userContext);
IPasswordHasher<ApplicationUser> hasher = new PasswordHasher<ApplicationUser>();
var validator = new UserValidator<ApplicationUser>();
var validators = new List<UserValidator<ApplicationUser>> { validator };
var result = new UserManager<ApplicationUser>(userstore, null, hasher, validators, null, null, null, null, _userLogger);
This is done in a helper class, and the result
is returned to the calling class, my controller.
In my controller I make the following call:
var user = await _userManager.GetUserAsync(User);
...however, user
is always null. I am assuming that some of the nulls
I'm passing in to the UserManager
constructor need to be filled in, but I'm only guessing. I actually got the basis for this code from another SO questions that I'm having trouble locating right now.
I don't think there's any magic in what I'm doing to configure some of the other dependencies. I use a DbContext
called ApplicationDbContext
that looks like so:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
I wire it up in Startup.cs
as such:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection")));
And I have an AppliactionUser
that comes in from a shared project.
When I do a:
var users = userManager.Users.ToList();
I get a list of all the expected users.
Why does the call to GetUserAsync
return null
?
Edit & Update
I just wanted to clarify that I am indeed using DI throughout the project, I just can't use it for UserManager
. The reason is that the dependencies are typically wired up for it through the .AddIdentity()
call, which we're not using on this project. Adding the default identity services trumps the OIDC configuration we're using, adds middleware we aren't using and prevents the user from properly authenticating.
The UserManager
is indeed the normal ASP.NET Core one. But the difference is that we're using OIDC to log the user in.
The ApplicationUser
was being returned as null
because the expected claims were not present on the authenticated user. The UserManager
is wired up correctly, save a config change that allows the user to be resolved by a differently named claim.
We are using IdentityServer 4 as the backing identity provider on the project. The claim type that identifies the user is called sub
, which is not normally inspected by the UserManager
.
In the end, I created a quick class (which I'll likely be able to refactor out to something inline) that looks like so:
public class OptionsProvider : IOptions<IdentityOptions>
{
public IdentityOptions Value { get
{
var result = new IdentityOptions();
result.ClaimsIdentity = new ClaimsIdentityOptions { UserIdClaimType = "sub" };
return result;
}
}
}
Next I updated the instantiation of the UserManager
to include the options:
var result = new UserManager<ApplicationUser>(
userstore,
new OptionsProvider(),
hasher,
validators,
null, null, null, null,
_userLogger);
This did the trick. Thanks again to @trailmax for pointing me at the source, which I should admittedly do a little more often.