I've created a custom IUserStore<TUser,int>
for my application. I've implemented the interfaces I need,
IUserStore<TUser, int>,
IUserRoleStore<TUser, int>,
IUserLockoutStore<TUser, int>,
IUserPasswordStore<TUser, int>
but when I call
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
I get an exception saying
Store does not implement IUserTwoFactorStore<TUser>.
I'm not using two factor authentication anywhere in my application. Why does it expect me to implement that interface? Is it required that I implement all of these interfaces, even if I don't actually use them?
The IUserStore<TUser> interface is the only interface you must implement in the user store.
A user store is the database where information about the users and user roles is stored, including log-in name, password, first name, last name, and e-mail address. The user stores of all WSO2 Carbon-based products are embedded H2 databases except for WSO2 Identity Server, which has an embedded LDAP as its user store.
IdentityResult(Boolean) Constructor that takes whether the result is successful. IdentityResult(IEnumerable<String>) Initializes a new instance of the IdentityResult class with the specified error messages.
ASP.NET Core Identity: Is an API that supports user interface (UI) login functionality. Manages users, passwords, profile data, roles, claims, tokens, email confirmation, and more.
ASP.NET Identity 2.0: Customizing Users and Roles. The ASP.NET Identity team released the Identity 2.0 framework RTM back in march. The new release contained significant additions to the functionality found in the original 1.0 release, and introduced some breaking changes as well.
ASP.NET Core Identity is an extensible system which enables you to create a custom storage provider and connect it to your app. This topic describes how to create a customized storage provider for ASP.NET Core Identity. It covers the important concepts for creating your own storage provider, but isn't a step-by-step walkthrough.
Managers are high-level classes which an application developer uses to perform operations, such as creating a user, in the ASP.NET Identity system. Stores are lower-level classes that specify how entities, such as users and roles, are persisted.
ASP.NET Core Identity consists of classes called managers and stores. Managers are high-level classes which an app developer uses to perform operations, such as creating an Identity user. Stores are lower-level classes that specify how entities, such as users and roles, are persisted.
Actually the IUserTwoFactorStore
interface is really simple, so far my implementation (I don't use two factor auth either) is this:
....
public Task<bool> GetTwoFactorEnabledAsync(User user)
{
return Task.FromResult(false);
}
public Task SetTwoFactorEnabledAsync(User user, bool enabled)
{
throw new NotImplementedException();
}
It works, although I just did it couple minutes ago and didn't test whole app thoroughly.
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<TUser, TKey> : SignInManager<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
public EnhancedSignInManager(
UserManager<TUser, TKey> 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<SignInStatus> 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<SignInStatus> 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With