如何在SQL Server上更改ASP.Net Identity 2以创建newSequentialId主键?

时间:2015-03-12 09:57:36

标签: asp.net asp.net-mvc asp.net-mvc-5 asp.net-identity asp.net-identity-2

我有一个ASP.NET身份2实现(没有用户数据,只有基表),我有一个类型为UNIQUEIDENTIFIER的userId。

应用程序首先是代码,我使用的是EF6。

这里是DDL:

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]                   UNIQUEIDENTIFIER NOT NULL,
    [FirstName]            NVARCHAR (MAX) NULL,
    [LastName]             NVARCHAR (MAX) NULL,
    [Email]                NVARCHAR (256) NULL,
    [EmailConfirmed]       BIT            NOT NULL,
    [PasswordHash]         NVARCHAR (MAX) NULL,
    [SecurityStamp]        NVARCHAR (MAX) NULL,
    [PhoneNumber]          NVARCHAR (MAX) NULL,
    [PhoneNumberConfirmed] BIT            NOT NULL,
    [TwoFactorEnabled]     BIT            NOT NULL,
    [LockoutEndDateUtc]    DATETIME       NULL,
    [LockoutEnabled]       BIT            NOT NULL,
    [AccessFailedCount]    INT            NOT NULL,
    [UserName]             NVARCHAR (256) NOT NULL,
    [SubjectId]            INT            DEFAULT ((0)) NOT NULL,
    [SubjectIds]           VARCHAR (50)   NULL,
    [OrganizationId]       INT            DEFAULT ((0)) NOT NULL,
    [OrganizationIds]      VARCHAR (50)   NULL,
    [RoleId]               INT            DEFAULT ((0)) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC)
);


GO
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex]
    ON [dbo].[AspNetUsers]([UserName] ASC);

我知道GUID创建正常是正常的GUID。

有人可以告诉我如何创建一个新的序列GUID吗?

请注意

我正在寻找使用ASP.Net Identity 2的正确方法。特别是我想知道Identity 2 UserManager等是否需要进行任何更改。

3 个答案:

答案 0 :(得分:3)

我终于能够构建项目并运行它。使用Fluent API创建后,newsequentialid()被分配给ID字段:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<ApplicationUser>().Property(t => t.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<CustomUserRole>().HasKey(x => new
        {
            x.RoleId,
            x.UserId
        });

        modelBuilder.Entity<CustomUserLogin>().HasKey(x => new
        {
            x.UserId,
            x.ProviderKey,
            x.LoginProvider
        });
    }

结果是SQL表编写为:

/****** Object:  Table [dbo].[AspNetUsers]    Script Date: 4/11/2015 3:40:51 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[AspNetUsers](
    [Id] [uniqueidentifier] NOT NULL,
    [Email] [nvarchar](256) NULL,
    [EmailConfirmed] [bit] NOT NULL,
    [PasswordHash] [nvarchar](max) NULL,
    [SecurityStamp] [nvarchar](max) NULL,
    [PhoneNumber] [nvarchar](max) NULL,
    [PhoneNumberConfirmed] [bit] NOT NULL,
    [TwoFactorEnabled] [bit] NOT NULL,
    [LockoutEndDateUtc] [datetime] NULL,
    [LockoutEnabled] [bit] NOT NULL,
    [AccessFailedCount] [int] NOT NULL,
    [UserName] [nvarchar](256) NOT NULL,
 CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

ALTER TABLE [dbo].[AspNetUsers] ADD  DEFAULT (newsequentialid()) FOR [Id]
GO

必须更改其他实体类型:

public class ApplicationUser : IdentityUser<Guid, CustomUserLogin, CustomUserRole,
    CustomUserClaim>
{


    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override Guid Id { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, Guid> 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 CustomUserRole : IdentityUserRole<Guid> { }
public class CustomUserClaim : IdentityUserClaim<Guid> { }
public class CustomUserLogin : IdentityUserLogin<Guid> { }

public class CustomRole : IdentityRole<Guid, CustomUserRole>
{
    public CustomRole() { }
    public CustomRole(string name) { Name = name; }
}

public class CustomUserStore : UserStore<ApplicationUser, CustomRole, Guid,
    CustomUserLogin, CustomUserRole, CustomUserClaim>
{
    public CustomUserStore(ApplicationDbContext context)
        : base(context)
    {
    }
}

public class CustomRoleStore : RoleStore<CustomRole, Guid, CustomUserRole>
{
    public CustomRoleStore(ApplicationDbContext context)
        : base(context)
    {
    }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole,
    Guid, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

在Startup.Auth.cs中,我改变了

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator
                    .OnValidateIdentity<ApplicationUserManager, ApplicationUser, Guid>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentityCallback: (manager, user) =>
                            user.GenerateUserIdentityAsync(manager),
                        getUserIdCallback: (id) => new Guid(id.GetUserId()))
            }
        });            
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

在IdentityConfig.cs中,我更改了ApplicationUserManager

下面:

public class ApplicationUserManager : UserManager<ApplicationUser, Guid>
{
    public ApplicationUserManager(IUserStore<ApplicationUser, Guid> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var manager = new ApplicationUserManager(
            new CustomUserStore(context.Get<ApplicationDbContext>()));
        // Configure validation logic for usernames             manager.UserValidator = new UserValidator<ApplicationUser>(manager)

        manager.UserValidator = new UserValidator<ApplicationUser, Guid>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

并且

        manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser, Guid>
        {
            MessageFormat = "Your security code is {0}"
        });
        manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser, Guid>
        {
            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, Guid>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}

// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, Guid>

在ManageController.cs中,我添加了

public class ManageController : Controller
{
    private ApplicationSignInManager _signInManager;
    private ApplicationUserManager _userManager;
    private Guid userGuidId;

    public ManageController()
    {
        userGuidId= new Guid(User.Identity.GetUserId());
    }

在我看到userGuidId

的所有地方取代userId

我必须在这里使用ToString()

BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userGuidId.ToString())

在帐户控制器中,我似乎只是改变了

    [AllowAnonymous]
    public async Task<ActionResult> ConfirmEmail(string userId, string code)
    {
        Guid GuidUserId = new Guid(userId);
        if (userId == null || code == null)
        {
            return View("Error");
        }
        var result = await UserManager.ConfirmEmailAsync(GuidUserId, code);
        return View(result.Succeeded ? "ConfirmEmail" : "Error");
    }

答案 1 :(得分:1)

首先创建基于“IdentityUser”类的非通用版本......

public class AppUserClaim : IdentityUserClaim<Guid> { }
public class AppUserLogin : IdentityUserLogin<Guid> { }
public class AppUserRole : IdentityUserRole<Guid> { }

...然后IdentityRoleUserStore以及`UserManager ...

相同
public class AppRole : IdentityRole<Guid, AppUserRole> 
{ 
}

public class AppUserStore : UserStore<AppUser, AppRole, Guid, AppUserLogin, AppUserRole, AppUserClaim>
{
    public AppUserStore(DbContext context)
        : base(context)
    {
    }
}

public class AppUserManager : UserManager<AppUser, Guid>
{
    public AppUserManager(IUserStore<AppUser, Guid> store)
        : base(store)
    {
    }
}

...最后是IdentityDbContext ...

public class AppIdentityContext : IdentityDbContext<AppUser, AppRole, Guid, AppUserLogin, AppUserRole, AppUserClaim>
{
    public AppIdentityContext()
        : base("name=AspNetIdentity")
    {
    }
}

在所有这些新类中,您会注意到基类使用Identity类的通用版本,我们正在使用AppUserClaimAppUserLoginAppUserRole和{{1}代替身份对应物。

对于用户,我们创建了一个名为AppRole的类,该类将派生自AppUser

IdentityUser

在构造函数中,我们使用public class AppUser : IdentityUser<Guid, AppUserLogin, AppUserRole, AppUserClaim> { [DllImport("rpcrt4.dll", SetLastError = true)] private static extern int UuidCreateSequential(out Guid guid); private Guid _id; public AppUser() { UuidCreateSequential(out _id); } /// <summary> /// User ID (Primary Key) /// </summary> public override Guid Id { get { return _id; } set { _id = value; } } } 函数创建一个新ID,并通过UuidCreateSequential属性返回该ID。我想在数据库中设置Id列以使用Id作为默认值并使用它而不是newsequentialid(),但我还没有解决这个问题。

在控制器操作中使用:

DllImport

有几点需要注意:

  1. 如果您使用的是现有数据库,即使用SQL脚本创建的数据库,public async Task<ActionResult> ActionName() { AppIdentityContext dbContext = new AppIdentityContext(); AppUserStore store = new AppUserStore(dbContext); AppUserManager manager = new AppUserManager(store); AppUser user = new AppUser { UserName = "<name>", Email = "<email>" }; await manager.CreateAsync(user); return this.View(); } 中的Id列为AspNetUsers,则需要更改跟随列到nvarchar

    • AspNetUsers.Id
    • AspNetRoles.Id
    • AspNetUserRoles.UserId
    • AspNetUserRoles.RoleId
  2. 在ASP.NET MVC控制器中的uniqueidentifier接口上使用GetUserId扩展方法,即IIdentity,将返回this.User.Identity.GetUserId()所以您将拥有在将返回值转换为字符串时使用以下内容:

    string

    此方法有一个通用版本,但它下面使用new Guid(this.User.Identity.GetUserId()),并且要求在实现Convert.ChangeTypeIConvertable中传递的值不会。

  3. 我无法对此进行全面测试,但希望如果它不能完全满足您的需求,它将提供有用的基础。

    更新#1 :以下是我完成的步骤:

    1. 使用“无身份验证”创建新的ASP.NET MVC应用程序
    2. 添加以下NuGet包

      • 的EntityFramework
      • Microsoft.AspNet.Identity.Core
      • Microsoft.AspNet.Identity.EntityFramework
    3. 将所有代码示例添加到Guid文件夹中名为Identity.cs的文件

      注意:排除控制器操作示例..这将在步骤#6中完成

    4. App_Start

    5. 中删除所有实体框架部分
    6. 向名为web.config
    7. web.config添加新的连接字符串
    8. 将控制器操作示例添加到AspNetIdentity上的Index操作,并替换HomeController<name>部分
    9. 将新的空数据库<email>添加到SQL Server
    10. 运行应用程序
    11. 如果使用选择了个人用户帐户身份验证选项的ASP.NET MVC模板,则会出现一些必须修复的错误。这些主要集中在将AspNetIdentity类的引用更改为基于IdentityUser*的新类,并替换对AppUser*的调用以使用我原始答案中步骤#2中提供的代码示例。< / p>

答案 2 :(得分:0)

这对我来说是有用的,可以使角色用户类型为Guid的ID字段在默认值或绑定中具有newsequentialid()

  1. 删除Visual Studio中迁移文件夹中的 *。cs 文件
  2. 删除表 __ MigrationHistory 以及数据库中的所有 AspNet *
  3. 将以下代码添加到 ApplicationDbContext 类:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<ApplicationUser>().Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<ApplicationRole>().Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
    
  4. 在Visual Studio包管理器控制台中运行Add-Migration Initial
  5. 在Visual Studio包管理器控制台中运行Update-Database
  6. 警告:这将删除数据库中角色的所有用户