I\'ve created a custom IUserStore
for my application. I\'ve implemented the interfaces I need,
IUserStore,
I had the same problem. For the moment, as the SignInManager.SignInOrTwoFactor method blindly checks for the GetTwoFactorAuthentication it throws an exception when the UserStore doesn't implement the IUserTwoFactorStore.
I believe Microsoft intended that the SignInManager PasswordSignInAsync method must be overriden in a custom SignInManager class. Unfortunately I couldn't find any documentation or samples pointing so.
Here is the SignInManager wrapper class I implemented to solve this issue:
public class EnhancedSignInManager : SignInManager
where TUser : class, IUser
where TKey : IEquatable
{
public EnhancedSignInManager(
UserManager userManager,
IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override async Task SignInAsync(
TUser user,
bool isPersistent,
bool rememberBrowser)
{
var userIdentity = await CreateUserIdentityAsync(user).WithCurrentCulture();
// Clear any partial cookies from external or two factor partial sign ins
AuthenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
if (rememberBrowser)
{
var rememberBrowserIdentity = AuthenticationManager
.CreateTwoFactorRememberBrowserIdentity(ConvertIdToString(user.Id));
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = isPersistent },
userIdentity,
rememberBrowserIdentity);
}
else
{
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = isPersistent },
userIdentity);
}
}
private async Task SignInOrTwoFactor(TUser user, bool isPersistent)
{
var id = Convert.ToString(user.Id);
if (UserManager.SupportsUserTwoFactor
&& await UserManager.GetTwoFactorEnabledAsync(user.Id)
.WithCurrentCulture()
&& (await UserManager.GetValidTwoFactorProvidersAsync(user.Id)
.WithCurrentCulture()).Count > 0
&& !await AuthenticationManager.TwoFactorBrowserRememberedAsync(id)
.WithCurrentCulture())
{
var identity = new ClaimsIdentity(
DefaultAuthenticationTypes.TwoFactorCookie);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id));
AuthenticationManager.SignIn(identity);
return SignInStatus.RequiresVerification;
}
await SignInAsync(user, isPersistent, false).WithCurrentCulture();
return SignInStatus.Success;
}
public override async Task PasswordSignInAsync(
string userName,
string password,
bool isPersistent,
bool shouldLockout)
{
if (UserManager == null)
{
return SignInStatus.Failure;
}
var user = await UserManager.FindByNameAsync(userName).WithCurrentCulture();
if (user == null)
{
return SignInStatus.Failure;
}
if (UserManager.SupportsUserLockout
&& await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
{
return SignInStatus.LockedOut;
}
if (UserManager.SupportsUserPassword
&& await UserManager.CheckPasswordAsync(user, password)
.WithCurrentCulture())
{
return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
}
if (shouldLockout && UserManager.SupportsUserLockout)
{
// If lockout is requested, increment access failed count
// which might lock out the user
await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture();
if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
{
return SignInStatus.LockedOut;
}
}
return SignInStatus.Failure;
}
}
I hope it helps. Cheers