Search code examples
asp.netasp.net-mvcasp.net-identity

Change User Id type to int in ASP.NET Identity in VS2015


By default ASP.NET Identity in VS 2015 uses a string as a primary key for AspNet*** tables. I wanted to to use int-typed id's instead. After some research it turned out that different typed id's are supported by the framework out of the box. In the answer below I will show what changes to make to achieve that.

UPDATE: After adding my answer I found this blog post on asp.net site that describes the same but more comprehensive: http://www.asp.net/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity


Solution

    1. IdentityModels.cs change to this:

      // New derived classes
      public class UserRole : IdentityUserRole<int>
      {
      }
      
      public class UserClaim : IdentityUserClaim<int>
      {
      }
      
      public class UserLogin : IdentityUserLogin<int>
      {
      }
      
      public class Role : IdentityRole<int, UserRole>
      {
          public Role() { }
          public Role(string name) { Name = name; }
      }
      
      public class UserStore : UserStore<ApplicationUser, Role, int,
          UserLogin, UserRole, UserClaim>
      {
          public UserStore(ApplicationDbContext context): base(context)
          {
          }
      }
      
      public class RoleStore : RoleStore<Role, int, UserRole>
      {
          public RoleStore(ApplicationDbContext context): base(context)
          {
          }
      }
      
      // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
      public class ApplicationUser : IdentityUser<int, UserLogin, UserRole, UserClaim>
      {
          public DateTime? ActiveUntil;
      
          public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
          {
              // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
              var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
              // Add custom user claims here
              return userIdentity;
          }
      }
      
      public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, int,
          UserLogin, UserRole, UserClaim>
      {
          public ApplicationDbContext()
              : base("DefaultConnection")
          {
          }
      
          public static ApplicationDbContext Create()
          {
              return new ApplicationDbContext();
          }
      }
      
    2. In `App_Start\IdentityConfig.cs, change the following classes:

      public class ApplicationUserManager : UserManager<ApplicationUser, int>
      {
          public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
              : base(store)
          {
          }
      
          public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
          {
              var manager = new ApplicationUserManager(new UserStore(context.Get<ApplicationDbContext>()));
              // Configure validation logic for usernames
              manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
              {
                  AllowOnlyAlphanumericUserNames = false,
                  RequireUniqueEmail = true
              };
      
              // Configure validation logic for passwords
              manager.PasswordValidator = new PasswordValidator
              {
                  RequiredLength = 8,
                  // RequireNonLetterOrDigit = true,
                  RequireDigit = true,
                  RequireLowercase = true,
                  RequireUppercase = true,
              };
      
              // Configure user lockout defaults
              manager.UserLockoutEnabledByDefault = true;
              manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
              manager.MaxFailedAccessAttemptsBeforeLockout = 5;
      
              // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
              // You can write your own provider and plug it in here.
              manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser, int>
              {
                  MessageFormat = "Your security code is {0}"
              });
              manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser, int>
              {
                  Subject = "Security Code",
                  BodyFormat = "Your security code is {0}"
              });
              manager.EmailService = new EmailService();
              manager.SmsService = new SmsService();
              var dataProtectionProvider = options.DataProtectionProvider;
              if (dataProtectionProvider != null)
              {
                  manager.UserTokenProvider = 
                      new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
              }
              return manager;
          }
      }
      
      // Configure the application sign-in manager which is used in this application.
      public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
      {
          public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
              : base(userManager, authenticationManager)
          {
          }
      
          public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
          {
              return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
          }
      
          public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
          {
              return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
          }
      }
      
    3. In App_Start\Startup.Auth.cs change OnValidateIdentity property to this:

      OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
          validateInterval: TimeSpan.FromMinutes(30),
          regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
          getUserIdCallback: id => id.GetUserId<int>())
      
    4. Change ManageController to work with the new pk type:

    Replace all entries of User.Identity.GetUserId() to User.Identity.GetUserId<int>()

    There might be a couple of string id arguments that need to be changed to int, but that's about it.