如何将身份用户从MVC5应用程序迁移到ASP.NET Core 2.2应用程序

ntjbwcob  于 2022-12-30  发布在  .NET
关注(0)|答案(6)|浏览(265)

我有一个使用标识在MVC5上生成的Web应用程序。我希望将此项目转换为ASP.NET Core 2.2 Web应用程序。我创建了一个新的ASP.NET Core 2.2 Web应用程序,并将身份验证设置为“个人用户帐户”,然后通过执行these instructions将我的数据库添加到项目中。然后,我将一个新的“标识支架”项添加到项目中,添加了迁移并更新了数据库。
我注册了一个测试用户,当我检查SQL管理服务器时,我看到它为此项目创建了一个新数据库,尽管我的连接字符串是针对我的旧数据库的。
我想保留我的旧数据库,但转换它使用新的身份剃刀网页是内置在与ASP.NET核心。什么是最好的方式去做这件事?

oxf4rvwz

oxf4rvwz1#

升级身份表后,您可能需要更新现有用户口令散列。AspNetUsers表中的某些新列将具有NULL值。首先运行以下命令:

UPDATE AspNetUsers SET NormalizedEmail = UPPER(Email), NormalizedUserName = UPPER(UserName)
WHERE NormalizedEmail IS NULL

我们需要一种方法来区分哪些用户正在使用新的哈希版本。
一种方法是向IdentityUser添加新属性:

public class ApplicationUser : IdentityUser
{
    public PasswordHashVersion HashVersion { get; set; }

    public ApplicationUser()
    {
        this.HashVersion = PasswordHashVersion.Core;
    }
}

public enum PasswordHashVersion
{
    OldMvc,
    Core
}

现有用户将默认PasswordHashVersion等于零(OldMvc),新注册用户将默认为1(Core)。如果您有更聪明的方法来检测哈希值是来自新算法还是旧算法,则不需要这样做。
然后,我们创建一个自定义PasswordHash,它使用old default hash algorithm implementation

public class OldMvcPasswordHasher : PasswordHasher<ApplicationUser>
{
    public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
    {
        // if it's the new algorithm version, delegate the call to parent class
        if (user.HashVersion == PasswordHashVersion.Core)
            return base.VerifyHashedPassword(user, hashedPassword, providedPassword);

        byte[] buffer4;
        if (hashedPassword == null)
        {
            return PasswordVerificationResult.Failed;
        }
        if (providedPassword == null)
        {
            throw new ArgumentNullException("providedPassword");
        }
        byte[] src = Convert.FromBase64String(hashedPassword);
        if ((src.Length != 0x31) || (src[0] != 0))
        {
            return PasswordVerificationResult.Failed;
        }
        byte[] dst = new byte[0x10];
        Buffer.BlockCopy(src, 1, dst, 0, 0x10);
        byte[] buffer3 = new byte[0x20];
        Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(providedPassword, dst, 0x3e8))
        {
            buffer4 = bytes.GetBytes(0x20);
        }
        if (AreHashesEqual(buffer3, buffer4))
        {
            user.HashVersion = PasswordHashVersion.Core;
            return PasswordVerificationResult.SuccessRehashNeeded;
        }
        return PasswordVerificationResult.Failed;
    }

    private bool AreHashesEqual(byte[] firstHash, byte[] secondHash)
    {
        int _minHashLength = firstHash.Length <= secondHash.Length ? firstHash.Length : secondHash.Length;
        var xor = firstHash.Length ^ secondHash.Length;
        for (int i = 0; i < _minHashLength; i++)
            xor |= firstHash[i] ^ secondHash[i];
        return 0 == xor;
    }
}

此类继承了新的身份核心PasswordHasher。如果用户的密码哈希版本已经使用新算法(例如HashVersion = Core),则我们只需从使用新算法的PasswordHasher调用基方法。否则,使用旧身份算法验证密码。
如果密码匹配,我们将用户密码散列版本更新为Core,并返回PasswordVerificationResult.SuccessRehashNeeded以强制使用新算法更新现有散列。
最后,你需要确保你的自定义PasswordHasher正在被使用。将以下代码添加到ConfigureServices中的Startup.cs

// Replace the existing scoped IPasswordHasher<> implementation
services.Replace(new ServiceDescriptor(
    serviceType: typeof(IPasswordHasher<ApplicationUser>),
    implementationType: typeof(OldMvcPasswordHasher),
    ServiceLifetime.Scoped));

必须在对AddIdentityAddDefaultIdentityAddIdentityCore的任何调用之后添加此变量。
这将在用户进行身份验证时缓慢更新密码哈希。

zsbz8rwp

zsbz8rwp2#

我刚刚能够通过以下步骤成功地将一个.NET 4.5.2项目迁移到.NET Core 3.1
1.使用Scaffold-DbContext基于现有数据库1(https://www.entityframeworktutorial.net/efcore/create-model-for-existing-database-in-ef-core.aspx)创建模型

Scaffold-DbContext [-Connection] [-Provider] [-OutputDir] [-Context] [-Schemas>] [-Tables>] [-DataAnnotations] [-Force] [-Project] [-StartupProject] [<CommonParameters>]

1.从生成的上下文中删除所有与AspNet相关的表以及不再需要的.cs文件。
1.将base.OnModelCreating(modelBuilder);添加到上下文文件中生成的OnModelCreating方法中。2(https://stackoverflow.com/a/34786782/3093561)
1.运行以下脚本以更新/创建标识表3(https://stackoverflow.com/a/43377313/3093561) 4(https://stackoverflow.com/a/57074910/3093561)

ALTER TABLE ASPNETROLES
ADD
 ConcurrencyStamp VARCHAR(255) NULL,               
 NormalizedName VARCHAR(255) NULL

 DROP TABLE AspNetUserTokens

 CREATE TABLE [AspNetUserTokens] (
    [UserId]        NVARCHAR (450) NOT NULL,
    [LoginProvider] NVARCHAR (450) NOT NULL,
    [Name]          NVARCHAR (450) NOT NULL,
    [Value]         NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_AspNetUserTokens]
 PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [Name] ASC)
)

ALTER TABLE AspNetUsers
 ADD
 ConcurrencyStamp VARCHAR(255) NULL,
 LockoutEnd DATETIME NULL,
 NormalizedEmail VARCHAR(255) NULL,
 NormalizedUserName VARCHAR(255) NULL

DROP TABLE [AspNetRoleClaims]

CREATE TABLE [AspNetRoleClaims] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [ClaimType]  NVARCHAR (MAX) NULL,
    [ClaimValue] NVARCHAR (MAX) NULL,
    [RoleId]     NVARCHAR (128) NOT NULL,
    CONSTRAINT [PK_AspNetRoleClaims]
 PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId]
 FOREIGN KEY ([RoleId])
  REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE
)

GO
CREATE NONCLUSTERED INDEX [IX_AspNetRoleClaims_RoleId]
    ON [AspNetRoleClaims]([RoleId] ASC)

ALTER TABLE AspNetUserLogins
   ADD ProviderDisplayName VARCHAR(255) NULL

UPDATE AspNetUsers SET NormalizedEmail = UPPER(Email), NormalizedUserName = UPPER(UserName)
WHERE NormalizedEmail IS NULL

1.在Startup.cs文件上,设置密码哈希兼容模式以考虑IdentityV 2

services.Configure<PasswordHasherOptions>(options => options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2);
aydmsdu9

aydmsdu93#

另一种解决方案是将数据导出/导入到新表中,我之所以这样做是出于几个不同的原因,但最终我不想修改原始源表,以防我需要快速而轻松地恢复它。
长话短说,您可以直接将旧数据导入/导出到新的Identity表中,另外唯一需要的是规范化的用户名和电子邮件值。
如果Identity可以在内部处理这些问题,就太好了,因为它可以在用户第一次登录时处理(更新)新的密码哈希、安全戳和并发戳而不会出现问题。
超级快速和简单的方法,我迁移我的用户与完整的密码:

**1)**将旧版本Identity上的用户表导出到CSV文件。
**2)**在Excel中打开该csv文件,并向CSV文件中添加三列,用于两个缺失的规范化列(用户名和电子邮件)和一个缺失的并发戳列(实际上不需要并发列)。
**3)**在第一个空白的规范化列(通常是c2)中,添加Excel公式=UPPER(b2)(其中b2是您尝试规范化的第一个值所在的字段...例如,直接导出时用户名=b2或电子邮件=d2,您将规范化列放在非规范化列旁边)。
**4)**将该公式向下拖动到电子表格的末尾,将所有用户名和电子邮件规范为大写值(即,所有大写=规范化)。
**5)**将大写值从电子表格中复制出来,粘贴到一个空的记事本文件中......然后将它们复制回电子表格中的同一个位置(这会用规范化值覆盖公式。Excel可能足够聪明,可以摆脱公式,并将规范化值保存在CSV保存中,但我没有测试它)。
**6)**将电子表格保存为CSV并将其导入到新身份AspnetUsers表中。

并发戳可以留空,用户第一次登录时,最新的标识将处理所有其他事务。
如果您在新版本中没有启用该功能,而在旧版本中启用了该功能,则Identity也不会登录用户名(因此您需要启用该功能或将用户名转换为相关的电子邮件地址,然后才能成功登录)。
这并不漂亮,但对于一次性工作,我用这种方法将我的用户从Identity 4.0.30319迁移到Core 2.2只花了不到15分钟,而且不需要更改密码。我花了比迁移用户更长的时间来输入所有这些内容。希望它能有所帮助。

l0oc07j2

l0oc07j24#

我已经编写了用于迁移到AspNetCore Identity的SQL脚本。
此脚本AspNet Identity完全向后兼容,因为我向表中添加了新列并扩展了已存在的列。
让我们看一下通过方案比较生成的屏幕截图:

你可以看到最后的剧本

BEGIN TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET XACT_ABORT ON;

GO
PRINT N'Starting dropping constraints';

GO
ALTER TABLE [dbo].[AspNetUserRoles]
    DROP CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId];

GO
ALTER TABLE [dbo].[AspNetUserRoles]
    DROP CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId];

GO
ALTER TABLE [dbo].[AspNetUserClaims]
    DROP CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId];

GO
ALTER TABLE [dbo].[AspNetUserLogins]
    DROP CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId];

-----------------------------------------------------------------------------
GO
PRINT N'Starting rebuilding table [dbo].[AspNetRoles]...';

GO
BEGIN TRANSACTION;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SET XACT_ABORT ON;

    CREATE TABLE [dbo].[tmp_ms_xx_AspNetRoles] (
        [Id]               NVARCHAR (450) NOT NULL,
        [Name]             NVARCHAR (256) NULL,
        [NormalizedName]   NVARCHAR (256) NULL,
        [ConcurrencyStamp] NVARCHAR (MAX) NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_AspNetRoles1] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (FILLFACTOR = 80)
    );

    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[AspNetRoles])
        BEGIN
            INSERT INTO [dbo].[tmp_ms_xx_AspNetRoles] ([Id], [Name], [NormalizedName], [ConcurrencyStamp])
            SELECT   [Id],
                     [Name],
                     UPPER([Name]),
                     NEWID()
            FROM     [dbo].[AspNetRoles]
            ORDER BY [Id] ASC;
        END

    DROP TABLE [dbo].[AspNetRoles];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_AspNetRoles]', N'AspNetRoles';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_AspNetRoles1]', N'PK_AspNetRoles', N'OBJECT';

COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

GO
CREATE UNIQUE NONCLUSTERED INDEX [RoleNameIndex]
    ON [dbo].[AspNetRoles]([Name] ASC) WHERE ([Name] IS NOT NULL) WITH (FILLFACTOR = 80);

GO
CREATE UNIQUE NONCLUSTERED INDEX [RoleNormalizedNameIndex]
    ON [dbo].[AspNetRoles]([NormalizedName] ASC) WHERE ([NormalizedName] IS NOT NULL) WITH (FILLFACTOR = 80);

-------------------------------------------------------------------
GO
PRINT N'Starting rebuilding table [dbo].[AspNetUserClaims]...';

GO
BEGIN TRANSACTION;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SET XACT_ABORT ON;

    CREATE TABLE [dbo].[tmp_ms_xx_AspNetUserClaims] (
        [Id]         INT            IDENTITY (1, 1) NOT NULL,
        [UserId]     NVARCHAR (450) NOT NULL,
        [ClaimType]  NVARCHAR (MAX) NULL,
        [ClaimValue] NVARCHAR (MAX) NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_AspNetUserClaims1] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (FILLFACTOR = 80)
    );

    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[AspNetUserClaims])
        BEGIN
            SET IDENTITY_INSERT [dbo].[tmp_ms_xx_AspNetUserClaims] ON;
            INSERT INTO [dbo].[tmp_ms_xx_AspNetUserClaims] ([Id], [UserId], [ClaimType], [ClaimValue])
            SELECT   [Id],
                     [UserId],
                     [ClaimType],
                     [ClaimValue]
            FROM     [dbo].[AspNetUserClaims]
            ORDER BY [Id] ASC;
            SET IDENTITY_INSERT [dbo].[tmp_ms_xx_AspNetUserClaims] OFF;
        END

    DROP TABLE [dbo].[AspNetUserClaims];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_AspNetUserClaims]', N'AspNetUserClaims';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_AspNetUserClaims1]', N'PK_AspNetUserClaims', N'OBJECT';

COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

GO
CREATE NONCLUSTERED INDEX [IX_AspNetUserClaims_UserId]
    ON [dbo].[AspNetUserClaims]([UserId] ASC) WITH (FILLFACTOR = 80);

-------------------------------------------------------------------
GO
PRINT N'Starting rebuilding table [dbo].[AspNetUserLogins]...';

GO
BEGIN TRANSACTION;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SET XACT_ABORT ON;

    CREATE TABLE [dbo].[tmp_ms_xx_AspNetUserLogins] (
        [LoginProvider]       NVARCHAR (450) NOT NULL,
        [ProviderKey]         NVARCHAR (450) NOT NULL,
        [ProviderDisplayName] NVARCHAR (MAX) NULL,
        [UserId]              NVARCHAR (450) NOT NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_AspNetUserLogins1] PRIMARY KEY CLUSTERED ([LoginProvider] ASC, [ProviderKey] ASC, [UserId] ASC) WITH (FILLFACTOR = 80)
    );

    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[AspNetUserLogins])
        BEGIN
            INSERT INTO [dbo].[tmp_ms_xx_AspNetUserLogins] ([LoginProvider], [ProviderKey], [UserId])
            SELECT   [LoginProvider],
                     [ProviderKey],
                     [UserId]
            FROM     [dbo].[AspNetUserLogins]
            ORDER BY [LoginProvider] ASC, [ProviderKey] ASC;
        END

    DROP TABLE [dbo].[AspNetUserLogins];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_AspNetUserLogins]', N'AspNetUserLogins';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_AspNetUserLogins1]', N'PK_AspNetUserLogins', N'OBJECT';
COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

GO
CREATE NONCLUSTERED INDEX [IX_AspNetUserLogins_UserId]
    ON [dbo].[AspNetUserLogins]([UserId] ASC) WITH (FILLFACTOR = 80);

-------------------------------------------------------------------
GO
PRINT N'Starting rebuilding table [dbo].[AspNetUserRoles]...';

GO
BEGIN TRANSACTION;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SET XACT_ABORT ON;

    CREATE TABLE [dbo].[tmp_ms_xx_AspNetUserRoles] (
        [UserId] NVARCHAR (450) NOT NULL,
        [RoleId] NVARCHAR (450) NOT NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_AspNetUserRoles1] PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC) WITH (FILLFACTOR = 80)
    );

    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[AspNetUserRoles])
        BEGIN
            INSERT INTO [dbo].[tmp_ms_xx_AspNetUserRoles] ([UserId], [RoleId])
            SELECT   [UserId],
                     [RoleId]
            FROM     [dbo].[AspNetUserRoles]
            ORDER BY [UserId] ASC, [RoleId] ASC;
        END

    DROP TABLE [dbo].[AspNetUserRoles];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_AspNetUserRoles]', N'AspNetUserRoles';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_AspNetUserRoles1]', N'PK_AspNetUserRoles', N'OBJECT';

COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

GO
CREATE NONCLUSTERED INDEX [IX_AspNetUserRoles_RoleId]
    ON [dbo].[AspNetUserRoles]([RoleId] ASC) WITH (FILLFACTOR = 80);
-------------------------------------------------------------------
GO
PRINT N'Starting rebuilding table [dbo].[AspNetUsers]...';

GO
BEGIN TRANSACTION;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SET XACT_ABORT ON;

    CREATE TABLE [dbo].[tmp_ms_xx_AspNetUsers] (
        [Id]                   NVARCHAR (450)     NOT NULL,
        [Email]                NVARCHAR (256)     NULL,
        [NormalizedEmail]      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,
        [LockoutEnd]           DATETIMEOFFSET (7) NULL,
        [LockoutEnabled]       BIT                NOT NULL,
        [AccessFailedCount]    INT                NOT NULL,
        [UserName]             NVARCHAR (256)     NULL,
        [NormalizedUserName]   NVARCHAR (256)     NULL,
        [ConcurrencyStamp]     NVARCHAR (MAX)     NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_AspNetUsers1] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (FILLFACTOR = 80)
    );

    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[AspNetUsers])
        BEGIN
            INSERT INTO [dbo].[tmp_ms_xx_AspNetUsers] (
                     [Id], 
                     [Email],
                     [NormalizedEmail],
                     [EmailConfirmed],
                     [PasswordHash],
                     [SecurityStamp],
                     [PhoneNumber],
                     [PhoneNumberConfirmed],
                     [TwoFactorEnabled],
                     [LockoutEnabled],
                     [AccessFailedCount],
                     [UserName],
                     [NormalizedUserName],
                     [ConcurrencyStamp])
            SELECT   [Id],
                     [Email],
                     UPPER([Email]),
                     [EmailConfirmed],
                     [PasswordHash],
                     [SecurityStamp],
                     [PhoneNumber],
                     [PhoneNumberConfirmed],
                     [TwoFactorEnabled],
                     [LockoutEnabled],
                     [AccessFailedCount],
                     [UserName],
                     UPPER([UserName]),
                     NEWID()
            FROM     [dbo].[AspNetUsers]
            ORDER BY [Id] ASC;
        END

    DROP TABLE [dbo].[AspNetUsers];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_AspNetUsers]', N'AspNetUsers';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_AspNetUsers1]', N'PK_AspNetUsers', N'OBJECT';

COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

GO
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex]
    ON [dbo].[AspNetUsers]([UserName] ASC) WHERE ([UserName] IS NOT NULL) WITH (FILLFACTOR = 80);

GO
CREATE UNIQUE NONCLUSTERED INDEX [NormalizedUserNameIndex]
    ON [dbo].[AspNetUsers]([NormalizedUserName] ASC) WHERE ([NormalizedUserName] IS NOT NULL) WITH (FILLFACTOR = 80);

GO
CREATE NONCLUSTERED INDEX [EmailIndex]
    ON [dbo].[AspNetUsers]([NormalizedEmail] ASC) WITH (FILLFACTOR = 80);

-------------------------------------------------------------------
GO
CREATE TABLE [dbo].[AspNetRoleClaims] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [RoleId]     NVARCHAR (450) NOT NULL,
    [ClaimType]  NVARCHAR (MAX) NULL,
    [ClaimValue] NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_AspNetRoleClaims] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (FILLFACTOR = 80)
);

GO
CREATE NONCLUSTERED INDEX [IX_AspNetRoleClaims_RoleId]
    ON [dbo].[AspNetRoleClaims]([RoleId] ASC) WITH (FILLFACTOR = 80);

-------------------------------------------------------------------
GO
PRINT N'Creating [dbo].[AspNetUserTokens]...';

GO
CREATE TABLE [dbo].[AspNetUserTokens] (
    [UserId]        NVARCHAR (450) NOT NULL,
    [LoginProvider] NVARCHAR (450) NOT NULL,
    [Name]          NVARCHAR (450) NOT NULL,
    [Value]         NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [Name] ASC) WITH (FILLFACTOR = 80)
);

-------------------------------------------------------------------
GO
PRINT N'Creating [dbo].[__EFMigrationsHistory]...';

GO
CREATE TABLE [dbo].[__EFMigrationsHistory] (
    [MigrationId]    NVARCHAR (150) NOT NULL,
    [ProductVersion] NVARCHAR (32)  NOT NULL,
    CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY CLUSTERED ([MigrationId] ASC) WITH (FILLFACTOR = 80)
);

--GO
--INSERT INTO [dbo].[__EFMigrationsHistory]
--           ([MigrationId], [ProductVersion])
--VALUES
--            ('20200406184458_InitialCreate',    '2.2.6-servicing-10079')
-------------------------------------------------------------------
GO
PRINT N'Creating constraints';

GO
ALTER TABLE [dbo].[AspNetUserLogins] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE;

GO
ALTER TABLE [dbo].[AspNetUserRoles] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE;

GO
ALTER TABLE [dbo].[AspNetUserRoles] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE;

GO
ALTER TABLE [dbo].[AspNetUserClaims] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE;

GO
ALTER TABLE [dbo].[AspNetRoleClaims] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE;

GO
ALTER TABLE [dbo].[AspNetUserTokens] WITH NOCHECK
    ADD CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE;
-------------------------------------------------------------------

GO
PRINT N'Update complete.';

COMMIT TRANSACTION;
pgccezyw

pgccezyw5#

虽然微软的documentation有些帮助,但最有帮助的信息在评论中。
我能够使用以下步骤迁移现有的数据库:

  • 创建一个新的ASP.net核心项目,并将其ModelSnapshot修改为

与EF6匹配。之后,您可以生成一个脚本,用于将EF6更改为EF Core。

  • 编写脚本以更新AspNetUsers表。在ASP.net核心

身份验证时使用NormalizedEmail,
NormalizedUserName列。因此我们需要更新这两列
利用我们现有的数据。
下面是更新表的脚本的GitHub链接。Migration.zip

7tofc5zh

7tofc5zh6#

我觉得应该重新开始。

步骤1:

创建迁移以创建新的Identity表。(我的新Identity nuget包版本为6.0.10

1.1为迁移创建DbContext

注意:我删除了创建旧Identity表的旧迁移文件和模型快照。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);

        // Create these Identity tables in a new schema
        builder.Entity<ApplicationUser>().ToTable("AspNetUsers", "mynewschema");
        builder.Entity<IdentityRole>().ToTable("AspNetRoles", "mynewschema");
        builder.Entity<IdentityUserClaim<string>>().ToTable("AspNetUserClaims", "mynewschema");
        builder.Entity<IdentityUserToken<string>>().ToTable("AspNetUserTokens", "mynewschema");
        builder.Entity<IdentityUserLogin<string>>().ToTable("AspNetUserLogins", "mynewschema");
        builder.Entity<IdentityRoleClaim<string>>().ToTable("AspNetRoleClaims", "mynewschema");
        builder.Entity<IdentityUserRole<string>>().ToTable("AspNetUserRoles", "mynewschema");
    }
}

ApplicationUser看起来像这样:

public class ApplicationUser : IdentityUser
{
}

1.2创建迁移:

PM> Add-Migration 'Create_new_identity_tables_on_new_schema'

第二步:

使用步骤1中的迁移创建新标识表:

PM> Update-Database

第三步:

使用以下脚本将数据从旧表复制到新表:

3.1复制用户:

INSERT INTO [mynewschema].[AspNetUsers] ([Id], [UserName], [NormalizedUserName], [Email], [NormalizedEmail], [EmailConfirmed], [PasswordHash], [SecurityStamp], [ConcurrencyStamp], [PhoneNumber], [PhoneNumberConfirmed], [TwoFactorEnabled], [LockoutEnd], [LockoutEnabled], [AccessFailedCount])
SELECT [Id], [UserName], UPPER([UserName]), [Email], UPPER([Email]), [EmailConfirmed], [PasswordHash], [SecurityStamp], '', [PhoneNumber], [PhoneNumberConfirmed], [TwoFactorEnabled], null, [LockoutEnabled], [AccessFailedCount] FROM [myoldschema].[AspNetUsers];

3.2复制角色:

INSERT INTO [mynewschema].[AspNetRoles] ([Id], [Name], [NormalizedName], [ConcurrencyStamp])
SELECT [Id], [Name], UPPER([Name]), null FROM [myoldschema].[AspNetRoles];

3.3将用户复制到角色Map:

INSERT INTO [mynewschema].[AspNetUserRoles] ([UserId], [RoleId])
SELECT [UserId], [RoleId] FROM [myoldschema].[AspNetUserRoles];

3.4您可能还需要复制其他表。我没有这样做,因为我没有使用其他表。

第四步:

您可能需要在Program.cs中添加 PasswordHasherCompatibilityMode。我没有这样做,因为在我的系统中,我们使用Active Directory密码验证用户。类似于this

builder.Services.Configure<PasswordHasherOptions>(options => options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2);

相关问题