使用SQL脚本创建ASP.NET标识表

pwd*_*dst 13 sql-server entity-framework code-first asp.net-identity

我试图将ASP.NET Identity合并到一个新的应用程序中,该应用程序当前使用SQL脚本来创建数据库模式.由于我们需要从其他表创建外键约束到用户表,因此非常希望ASP.NET标识表也在相同的脚本中创建.

我已经能够在IdentityModels.cs中创建的ApplicationUser类中扩展IdentityUser类

public class ApplicationUser : IdentityUser
{
    public ApplicationUser()
    {
        Sequence = 0;
        LastActivity = DateTime.Now;
    }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int NumericId
    {
        get;
        set;
    }

    [MaxLength(50), Required]
    public string DisplayName
    {
        get;
        set;
    }

    [MaxLength(50), Required]
    public string Description
    {
        get;
        set;
    }

    [IntegerValidator(MinValue = 0), Required]
    public int Sequence
    {
        get;
        set;
    }

    [MaxLength(50)]
    public string ExternalRef
    {
        get;
        set;
    }

    public DateTime? LoggedOn
    {
        get;
        set;
    }

    public DateTime? LoggedOff
    {
        get;
        set;
    }

    public DateTime LastActivity
    {
        get;
        set;
    }

    public int FailedLoginAttempts
    {
        get;
        set;
    }

    public DateTime? LockedOutUntil
    {
        get;
        set;
    }

    public int LockOutCycles
    {
        get;
        set;
    }

    public bool Approved
    {
        get;
        set;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用脚本创建了表格 -

CREATE TABLE [Users].[User] (
[Id] [nvarchar](128) NOT NULL
,[NumericId] [int] IDENTITY(1,1) NOT NULL
,[UserName] [nvarchar](50) NULL
,[PasswordHash] [nvarchar](max) NULL
,[SecurityStamp] [nvarchar](max) NULL
,[DisplayName] [nvarchar](50) NULL
,[Description] [nvarchar](50) NOT NULL
,[EmailAddress] [nvarchar](254) NOT NULL
,[Confirmed] [bit] NOT NULL
,[Sequence] [int] NOT NULL
,[ExternalRef] [nvarchar](50) NOT NULL
,[LoggedOn] [datetime] NULL
,[LoggedOff] [datetime] NULL
,[LastActivity] [datetime] NULL
,[FailedLoginAttempts] [int] NOT NULL
,[LockedOutUntil] [datetime] NULL
,[LockOutCycles] int NOT NULL
,[Approved] [bit] NOT NULL
,[Discriminator] [nvarchar](128) NOT NULL
,CONSTRAINT [PK_User] PRIMARY KEY NONCLUSTERED ([Id] ASC) WITH (
    PAD_INDEX = OFF
    ,STATISTICS_NORECOMPUTE = OFF
    ,IGNORE_DUP_KEY = OFF
    ,ALLOW_ROW_LOCKS = ON
    ,ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
,CONSTRAINT [IX_User_NumericId] UNIQUE CLUSTERED ([NumericId] ASC) WITH (
    PAD_INDEX = OFF
    ,STATISTICS_NORECOMPUTE = OFF
    ,IGNORE_DUP_KEY = OFF
    ,ALLOW_ROW_LOCKS = ON
    ,ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
,CONSTRAINT [IX_User_Name] UNIQUE NONCLUSTERED ([UserName] ASC) WITH (
    PAD_INDEX = OFF
    ,STATISTICS_NORECOMPUTE = OFF
    ,IGNORE_DUP_KEY = OFF
    ,ALLOW_ROW_LOCKS = ON
    ,ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [Users].[User] ADD CONSTRAINT [DF_User_Description] DEFAULT('')
FOR [Description]
GO

ALTER TABLE [Users].[User] ADD CONSTRAINT [DF_User_Sequence] DEFAULT((0))
FOR [Sequence]
GO

ALTER TABLE [Users].[User] ADD CONSTRAINT [DF_User_ExternalRef] DEFAULT('')
FOR [ExternalRef]
GO

ALTER TABLE [Users].[User] ADD CONSTRAINT [DF_User_FailedLoginAttempts] DEFAULT((0))
FOR [FailedLoginAttempts]
GO

ALTER TABLE [Users].[User] ADD CONSTRAINT [DF_User_LockOutCycles] DEFAULT((0))
FOR [LockOutCycles]
GO

CREATE NONCLUSTERED INDEX [IX_User_Sequence] ON [Users].[User] ([Sequence] ASC, [UserName] ASC)
    WITH (
            PAD_INDEX = OFF
            ,STATISTICS_NORECOMPUTE = OFF
            ,SORT_IN_TEMPDB = OFF
            ,IGNORE_DUP_KEY = OFF
            ,DROP_EXISTING = OFF
            ,ONLINE = OFF
            ,ALLOW_ROW_LOCKS = ON
            ,ALLOW_PAGE_LOCKS = ON
            ) ON [PRIMARY]
GO

CREATE TABLE [Users].[UserClaim](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ClaimType] [nvarchar](max) NULL,
    [ClaimValue] [nvarchar](max) NULL,
    [UserId] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_Users.UserClaims] 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 [Users].[UserClaim]  WITH CHECK ADD  CONSTRAINT [FK_Users.UserClaims_Users.User_User_Id] FOREIGN KEY([UserId])
REFERENCES [Users].[User] ([Id])
ON DELETE CASCADE
GO

ALTER TABLE [Users].[UserClaim] CHECK CONSTRAINT [FK_Users.UserClaims_Users.User_User_Id]
GO

CREATE TABLE [Users].[UserLogin](
    [UserId] [nvarchar](128) NOT NULL,
    [LoginProvider] [nvarchar](128) NOT NULL,
    [ProviderKey] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_Users.UserLogins] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC,
    [LoginProvider] ASC,
    [ProviderKey] ASC
)WITH (PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [Users].[UserLogin]  WITH CHECK ADD  CONSTRAINT [FK_Users.UserLogins_Users.User_UserId] FOREIGN KEY([UserId])
REFERENCES [Users].[User] ([Id])
ON DELETE CASCADE
GO

ALTER TABLE [Users].[UserLogin] CHECK CONSTRAINT [FK_Users.UserLogins_Users.User_UserId]

CREATE TABLE [Users].[ApplicationRole](
    [Id] [nvarchar](128) NOT NULL,
    [Name] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_Users.ApplicationRole] 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]


CREATE TABLE [Users].[UserRole](
    [UserId] [nvarchar](128) NOT NULL,
    [RoleId] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_Users.UserRole] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC,
    [RoleId] ASC
)WITH (PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [Users].[UserRole]  WITH CHECK ADD  CONSTRAINT [FK_Users.UserRole_Users.ApplicationRole_RoleId] FOREIGN KEY([RoleId])
REFERENCES [Users].[ApplicationRole] ([Id])
ON DELETE CASCADE
GO

ALTER TABLE [Users].[UserRole] CHECK CONSTRAINT [FK_Users.UserRole_Users.ApplicationRole_RoleId]
GO

ALTER TABLE [Users].[UserRole]  WITH CHECK ADD  CONSTRAINT [FK_Users.UserRole_Users.User_UserId] FOREIGN KEY([UserId])
REFERENCES [Users].[User] ([Id])
ON DELETE CASCADE
GO

ALTER TABLE [Users].[UserRole] CHECK CONSTRAINT [FK_Users.UserRole_Users.User_UserId]
GO

CREATE TABLE [Users].[Department](
    [Id] [int] IDENTITY(1, 1) NOT NULL
    ,[Name] [nvarchar](50) NOT NULL
    ,[Description] [nvarchar](50) NOT NULL
    ,[Sequence] [int] NOT NULL
 CONSTRAINT [PK_Users.Department] 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]

GO
Run Code Online (Sandbox Code Playgroud)

并使用OnModelCreating事件的覆盖将实体映射到表中 -

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<IdentityUser>().ToTable("User", "Users");

        modelBuilder.Entity<IdentityUser>().Property(iu => iu.Id).HasColumnName("Id");
        modelBuilder.Entity<IdentityUser>().Property(iu => iu.UserName).HasColumnName("UserName");
        modelBuilder.Entity<IdentityUser>().Property(iu => iu.Email).HasColumnName("EmailAddress").HasMaxLength(254).IsRequired();
        modelBuilder.Entity<IdentityUser>().Property(iu => iu.PasswordHash).HasColumnName("PasswordHash");
        modelBuilder.Entity<IdentityUser>().Property(iu => iu.SecurityStamp).HasColumnName("SecurityStamp");
        modelBuilder.Entity<IdentityUser>().Property(iu => iu.IsConfirmed).HasColumnName("Confirmed");

        modelBuilder.Entity<ApplicationUser>().HasKey(au => au.Id).ToTable("User", "Users"); //Specify our our own table names instead of the defaults

        modelBuilder.Entity<ApplicationUser>().Property(au => au.Id).HasColumnName("Id");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.NumericId).HasColumnName("NumericId");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.UserName).HasMaxLength(50).HasColumnName("UserName");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.PasswordHash).HasColumnName("PasswordHash");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.SecurityStamp).HasColumnName("SecurityStamp");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.DisplayName).HasColumnName("DisplayName");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.Description).HasColumnName("Description");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.Sequence).HasColumnName("Sequence");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.ExternalRef).HasColumnName("ExternalRef");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.LoggedOn).HasColumnName("LoggedOn");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.LoggedOff).HasColumnName("LoggedOff");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.LastActivity).HasColumnName("LastActivity");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.FailedLoginAttempts).IsOptional().HasColumnName("FailedLoginAttempts");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.LockedOutUntil).IsOptional().HasColumnName("LockedOutUntil");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.LockOutCycles).IsOptional().HasColumnName("LockOutCycles");
        modelBuilder.Entity<ApplicationUser>().Property(au => au.Approved).HasColumnName("Approved");

        modelBuilder.Entity<IdentityRole>().HasKey(ir => ir.Id).ToTable("ApplicationRole", "Users");

        modelBuilder.Entity<IdentityRole>().Property(ir => ir.Id).HasColumnName("Id");
        modelBuilder.Entity<IdentityRole>().Property(ir => ir.Name).HasColumnName("Name");

        modelBuilder.Entity<IdentityUserClaim>().HasKey(iuc => iuc.Id).ToTable("UserClaim", "Users");

        modelBuilder.Entity<IdentityUserClaim>().Property(iuc => iuc.Id).HasColumnName("Id");
        modelBuilder.Entity<IdentityUserClaim>().Property(iuc => iuc.ClaimType).HasColumnName("ClaimType");
        modelBuilder.Entity<IdentityUserClaim>().Property(iuc => iuc.ClaimValue).HasColumnName("ClaimValue");
        modelBuilder.Entity<IdentityUserClaim>().Property(iuc => iuc.UserId).HasColumnName("UserId");

        modelBuilder.Entity<IdentityUserLogin>().HasKey(iul => new { iul.UserId, iul.LoginProvider, iul.ProviderKey }).ToTable("UserLogin", "Users"); //Used for third party OAuth providers

        modelBuilder.Entity<IdentityUserLogin>().Property(iul => iul.UserId).HasColumnName("UserId");
        modelBuilder.Entity<IdentityUserLogin>().Property(iul => iul.LoginProvider).HasColumnName("LoginProvider");
        modelBuilder.Entity<IdentityUserLogin>().Property(iul => iul.ProviderKey).HasColumnName("ProviderKey");

        modelBuilder.Entity<IdentityUserRole>().HasKey(iur => new { iur.UserId, iur.RoleId }).ToTable("UserRole", "Users");

        modelBuilder.Entity<IdentityUserRole>().Property(ur => ur.UserId).HasColumnName("UserId");
        modelBuilder.Entity<IdentityUserRole>().Property(ur => ur.RoleId).HasColumnName("RoleId");
    }
Run Code Online (Sandbox Code Playgroud)

这适用于注册,并确实在注册后签名,但任何尝试在此之后登录都会导致 -

异常详细信息:System.Data.SqlClient.SqlException:

列名称'IdentityUser_Id'无效.

列名称'IdentityUser_Id'无效.

列名称"Id"无效.列名称'IdentityRole_Id'无效.

列名称'IdentityUser_Id'无效.

来源错误:

第337行:{

第338行:
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

第339行:
var identity = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);

第340行:
AuthenticationManager.SignIn(new AuthenticationProperties {IsPersistent = isPersistent},identity);

第341行:}

我相信这是ApplicationUser和IdentityUserRole实体之间的外键问题 - 这些实体存在于数据库中,但未在流畅的API映射中定义.IdentityUser是一个复杂类型的事实似乎导致EF假设根据生成的查询将列附加到IdentityUserRole表(名为"[User].[UserRole]") -

exec sp_executesql N'SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[RoleId] AS [RoleId], 
[Extent1].[IdentityRole_Id] AS [IdentityRole_Id], 
[Extent1].[IdentityUser_Id] AS [IdentityUser_Id]
FROM [Users].[UserRole] AS [Extent1]
WHERE ([Extent1].[IdentityUser_Id] IS NOT NULL) AND ([Extent1].[IdentityUser_Id] =    
@EntityKeyValue1)',N'@EntityKeyValue1 nvarchar(128)',
@EntityKeyValue1=N'2e16b5b5-6604-4f2c-9fbb-7cc3f5c9d4f3'
go
Run Code Online (Sandbox Code Playgroud)

如何从ApplicationUser/IdentityUser和IdentityRole类配置流畅API中的外键o指回"[Users].[User]"表,或从IdentityUserRole类指向用户和角色实体或表?外键已存在于SQL中.

Hao*_*ung 5

因此,默认情况下,新的1.1-alpha1位将接近以下内容.这可能是您在外键方面寻找的内容.注意:这与1.0略有不同,因为导航属性稍微改变了一下,以便能够指定主键类型:

我们正在尝试解决一些EF迁移/可扩展性问题,因此使用Identity 1.1-alpha1和即将发布的6.0.2/6.1 EF版本可能会更容易,但我不确定myget上是否有更新的EF包然而.

    var user = modelBuilder.Entity<TUser>()
        .ToTable("AspNetUsers");
    user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
    user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
    user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
    user.Property(u => u.UserName).IsRequired();

    modelBuilder.Entity<TUserRole>()
        .HasKey(r => new { r.UserId, r.RoleId })
        .ToTable("AspNetUserRoles");

    modelBuilder.Entity<TUserLogin>()
        .HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey})
        .ToTable("AspNetUserLogins");

    modelBuilder.Entity<TUserClaim>()
        .ToTable("AspNetUserClaims");

    var role = modelBuilder.Entity<TRole>()
        .ToTable("AspNetRoles");
    role.Property(r => r.Name).IsRequired();
    role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
Run Code Online (Sandbox Code Playgroud)

  • 我只想补充一点,你们这些人正在强迫身份下降.Asp.net会员资格非常漂亮,因为它刚刚起作用.我们有一个可以在VS中启动的配置网站来设置用户/角色等.有时我会收到构建简单应用程序的请求,而我没有时间花时间试图弄清楚如何使用Identity而不是比以前的会员系统更好的功能. (10认同)