Note: This is the second post in a 2 post tutorial on implementing Identity 2.0 without using EF, for post 1 go here.
Now we have our User and UserStore classes we can change the UserManager and SignInManager our application uses. These classes are in the App_Start/IdentityConfig.cs
file.
I split the classes out to their own files, ApplicationUserManager.cs
and ApplicationSignInManager.cs
respectively. In their unmodified state these classes inherit from the classes provided by the Identity library.
ApplicationUserManager
The manager provides many methods to use in our controllers, a few examples are:
public virtual Task<IdentityResult> ResetAccessFailedCountAsync(TKey userId);
public virtual Task<IdentityResult> ResetPasswordAsync(TKey userId, string token, string newPassword);
public virtual Task SendEmailAsync(TKey userId, string subject, string body);
The manager mainly delegates to classes it owns such as the user store to run these methods. The default template UserManager is shown below:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store) { }
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
[CONTENT REMOVED TO SAVE SPACE...]
return manager;
}
}
Because everything takes arguments based on interfaces we've already created our classes for, the rewrite is very simple. Firstly we replace all instances of ApplicationUser
with our class which implements IUser, in our case MyUser
:
public class ApplicationUserManager : UserManager<MyUser>
{
public ApplicationUserManager(IUserStore<MyUser> store)
: base(store)
{
this.UserValidator = new MyUserValidator<MyUser, string>();
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(new MyUserStore<MyUser>());
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<MyUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 3,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = true,
RequireUppercase = false
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = false;
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
return manager;
}
}
I set the password requirements to be super weak for manual testing because typing secure passwords repeatedly was too much like hard work!
We also remove the default UserStore
which depends on Entity Framework and insert our own MyUserStore
(which in this tutorial also depends on EF but with no requirement to pass a DbContext to the constructor). Additionally all parts setting up 2 Factor Auth are removed.