将现有网站从 SQL 成员身份迁移到 ASP.NET Identity

作者 :里克·安德森苏哈斯·乔希

本教程演示了将现有 Web 应用程序与使用 SQL 成员身份创建的用户和角色数据迁移到新的 ASP.NET 标识系统的步骤。 此方法涉及将现有数据库架构更改为 ASP.NET 标识所需的数据库架构,并将旧/新类中的挂钩更改为该架构。 采用此方法后,迁移数据库后,将毫不费力地处理对标识的未来更新。

在本教程中,我们将使用 Visual Studio 2010 创建 web 应用程序模板 (Web Forms) 创建用户和角色数据。 然后,我们将使用 SQL 脚本将现有数据库迁移到标识系统所需的表。 接下来,我们将安装必要的 NuGet 包,并添加新的帐户管理页,该页使用标识系统进行成员身份管理。 作为迁移测试,使用 SQL 成员身份创建的用户应能够登录,新用户应能够注册。 可在此处找到完整示例。 另请参阅 从 ASP.NET 成员身份迁移到 ASP.NET 标识

入门

使用 SQL 成员身份创建应用程序

  1. 我们需要从使用 SQL 成员身份并具有用户和角色数据的现有应用程序开始。 在本文中,让我们在 Visual Studio 2010 中创建一个 Web 应用程序。

    在 Visual Studio 2010 中创建 Web 应用程序的屏幕截图。

  2. 使用 ASP.NET 配置工具,创建 2 个用户: oldAdminUseroldUser。

    A S P 的屏幕截图。用于创建两个用户的 N E T 配置工具。

    用于管理所有安全性的网站管理工具的屏幕截图。

  3. 创建名为管理员的角色,并将“oldAdminUser”添加为该角色中的用户。

    作为该角色的用户创建的管理员角色的屏幕截图。

  4. 使用 Default.aspx 创建站点的管理员部分。 设置web.config文件中的授权标记,以便仅对管理员角色中的用户进行访问。 有关详细信息,可在此处找到 https://www.asp.net/web-forms/tutorials/security/roles/role-based-authorization-cs

    网站的管理员部分的屏幕截图。

  5. 在服务器资源管理器中查看数据库,以了解 SQL 成员身份系统创建的表。 用户登录数据存储在aspnet_Users和aspnet_Membership表中,角色数据存储在aspnet_Roles表中。 有关哪些用户位于aspnet_UsersInRoles表中存储哪些角色的信息。 对于基本成员身份管理,将上述表中的信息移植到 ASP.NET 标识系统就足够了。

    服务器资源管理器的屏幕截图,用于查看数据库,以了解 S Q L 成员身份系统创建的表。

迁移到 Visual Studio 2013

  1. 安装 Visual Studio Express 2013 for Web 或Visual Studio 2013以及最新更新

  2. 在已安装的 Visual Studio 版本中打开上述项目。 如果未在计算机上安装SQL Server Express,则打开项目时会显示提示,因为συμβολοσειρά σύνδεσης使用 SQL Express。 可以选择安装 SQL Express,也可以将συμβολοσειρά σύνδεσης更改为 LocalDb。 在本文中,我们将将其更改为 LocalDb。

  3. 打开web.config并从中更改συμβολοσειρά σύνδεσης。SQLExpress (LocalDb) v11.0。 从συμβολοσειρά σύνδεσης中删除“User Instance=true”。

    更改要迁移到Visual Studio 2013的συμβολοσειρά σύνδεσης的屏幕截图。

  4. 打开服务器资源管理器并验证是否可以观察表架构和数据。

  5. ASP.NET 标识系统适用于框架版本 4.5 或更高版本。 将应用程序重定向到 4.5 或更高版本。

    A S P 的屏幕截图。N E T 标识系统。

    生成项目以验证是否存在错误。

安装 Nuget 包

  1. 在Průzkumník řešení中,右键单击项目>“管理 NuGet 包”。 在搜索框中,输入“Asp.net 标识”。 在结果列表中选择包,然后单击“安装”。 单击“我接受”按钮接受许可协议。 请注意,此包将安装依赖项包:EntityFramework 和 Microsoft ASP.NET Identity Core。 同样,如果不想启用 OAuth 登录) ,请 (跳过最后 4 个 OWIN 包:

    • Microsoft.AspNet.Identity.Owin

    • Microsoft.Owin.Host.SystemWeb

    • Microsoft.Owin.Security.Facebook

    • Microsoft.Owin.Security.Google

    • Microsoft.Owin.Security.MicrosoftAccount

    • Microsoft.Owin.Security.Twitter

      在 Průzkumník řešení 中安装 Nuget 包的屏幕截图。

将数据库迁移到新的标识系统

下一步是将现有数据库迁移到 ASP.NET 标识系统所需的架构。 为此,我们将运行一个 SQL 脚本,其中包含一组命令来创建新表并将现有用户信息迁移到新表。 可在 此处找到脚本文件。

此脚本文件特定于此示例。 如果自定义或修改了使用 SQL 成员身份创建的表的架构,则需要相应地更改脚本。

如何生成用于架构迁移的 SQL 脚本

要使 ASP.NET 标识类能够使用现有用户的数据使用现用,我们需要将数据库架构迁移到 ASP.NET 标识所需的数据库架构。 可以通过添加新表并将现有信息复制到这些表来执行此操作。 默认情况下,ASP.NET 标识使用 EntityFramework 将标识模型类映射回数据库以存储/检索信息。 这些模型类实现定义用户和角色对象的核心标识接口。 数据库中的表和列基于这些模型类。 Identity v2.1.0 中的 EntityFramework 模型类及其属性定义如下

IdentityUser 类型 IdentityRole IdentityUserRole IdentityUserLogin IdentityUserClaim
ID 字符串 ID RoleId ProviderKey ID
用户名 string 名称 UserId UserId ClaimType
PasswordHash string LoginProvider ClaimValue
SecurityStamp string User_Id
电子邮件 字符串
EmailConfirmed bool
PhoneNumber string
PhoneNumberConfirmed bool
LockoutEnabled bool
LockoutEndDate DateTime
AccessFailedCount int

我们需要为其中每个模型提供与属性对应的列的表。 类和表之间的映射在方法IdentityDBContextOnModelCreating定义。 这称为配置流畅的 API 方法,可在 此处找到更多信息。 类的配置如下所述

主密钥 外键
IdentityUser AspnetUsers ID
IdentityRole AspnetRoles ID
IdentityUserRole AspnetUserRole UserId + RoleId User_Id-AspnetUsers> RoleId-AspnetRoles>
IdentityUserLogin AspnetUserLogins ProviderKey+UserId + LoginProvider UserId-AspnetUsers>
IdentityUserClaim AspnetUserClaims ID User_Id-AspnetUsers>

利用此信息,我们可以创建 SQL 语句以创建新表。 我们可以单独编写每个语句,也可以使用 EntityFramework PowerShell 命令生成整个脚本,然后根据需要进行编辑。 为此,在 VS 中,从“视图”或“工具”菜单打开包管理器控制台

  • 运行命令“Enable-Migrations”以启用 EntityFramework 迁移。
  • 运行命令“Add-migration initial”,该命令创建初始安装代码以在 C#/VB 中创建数据库。
  • 最后一步是运行“Update-Database –Script”命令,该命令基于模型类生成 SQL 脚本。

如果应用使用 SQLite 作为其标识数据存储,则不支持某些命令。 由于数据库引擎的限制, Alter 命令会引发以下异常:

“System.NotSupportedException:SQLite 不支持此迁移操作。

作为一种解决方法,请在数据库上运行 Code First 迁移以更改表。

此数据库生成脚本可用作开始,我们将进行其他更改来添加新列和复制数据。 其优点是,生成 _MigrationHistory 由 EntityFramework 用来修改数据库架构的表,当模型类为将来版本的 Identity 版本而更改时,该表会修改数据库架构。

除了标识用户模型类中的属性(即电子邮件、密码尝试、上次登录日期、上次锁定日期等)之外,SQL 成员身份用户信息还具有其他属性。这是有用的信息,我们希望它被传送到标识系统。 为此,可以将其他属性添加到用户模型,并将其映射回数据库中的表列。 可以通过添加对模型进行子类的 IdentityUser 类来执行此操作。 我们可以将属性添加到此自定义类,并编辑 SQL 脚本,以在创建表时添加相应的列。 本文进一步介绍了此类的代码。 添加新属性后用于创建 AspnetUsers 表的 SQL 脚本将是

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]            NVARCHAR (128) NOT NULL,
    [UserName]      NVARCHAR (MAX) NULL,
    [PasswordHash]  NVARCHAR (MAX) NULL,
    [SecurityStamp] NVARCHAR (MAX) NULL,
    [EmailConfirmed]       BIT            NOT NULL,
    [PhoneNumber]          NVARCHAR (MAX) NULL,
    [PhoneNumberConfirmed] BIT            NOT NULL,
    [TwoFactorEnabled]     BIT            NOT NULL,
    [LockoutEndDateUtc]    DATETIME       NULL,
    [LockoutEnabled]       BIT            NOT NULL,
    [AccessFailedCount]    INT            NOT NULL,
    [ApplicationId]                          UNIQUEIDENTIFIER NOT NULL,
    [LegacyPasswordHash]  NVARCHAR (MAX) NULL,
    [LoweredUserName]  NVARCHAR (256)   NOT NULL,
    [MobileAlias]      NVARCHAR (16)    DEFAULT (NULL) NULL,
    [IsAnonymous]      BIT              DEFAULT ((0)) NOT NULL,
    [LastActivityDate] DATETIME2         NOT NULL,
    [MobilePIN]                              NVARCHAR (16)    NULL,
    [Email]                                  NVARCHAR (256)   NULL,
    [LoweredEmail]                           NVARCHAR (256)   NULL,
    [PasswordQuestion]                       NVARCHAR (256)   NULL,
    [PasswordAnswer]                         NVARCHAR (128)   NULL,
    [IsApproved]                             BIT              NOT NULL,
    [IsLockedOut]                            BIT              NOT NULL,
    [CreateDate]                             DATETIME2               NOT NULL,
    [LastLoginDate]                          DATETIME2         NOT NULL,
    [LastPasswordChangedDate]                DATETIME2         NOT NULL,
    [LastLockoutDate]                        DATETIME2         NOT NULL,
    [FailedPasswordAttemptCount]             INT              NOT NULL,
    [FailedPasswordAttemptWindowStart]       DATETIME2         NOT NULL,
    [FailedPasswordAnswerAttemptCount]       INT              NOT NULL,
    [FailedPasswordAnswerAttemptWindowStart] DATETIME2         NOT NULL,
    [Comment]                                NTEXT            NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC),
    FOREIGN KEY ([ApplicationId]) REFERENCES [dbo].[aspnet_Applications] ([ApplicationId]),
);

接下来,我们需要将现有信息从 SQL 成员身份数据库复制到新添加的标识表。 可以通过 SQL 将数据直接从一个表复制到另一个表来完成。 若要将数据添加到表的行中,我们使用构造 INSERT INTO [Table] 。 若要从另一个表复制,可以使用该 INSERT INTO 语句和 SELECT 语句。 若要获取所有用户信息,我们需要查询 aspnet_Usersaspnet_Membership 表,并将数据复制到 AspNetUsers 表。 INSERT INTO我们使用和SELECTJOINLEFT OUTER JOIN语句。 有关在表之间查询和复制数据的详细信息,请参阅 链接。 此外,AspnetUserLogins 和 AspnetUserClaims 表是空的,因为默认情况下 SQL 成员身份中没有映射到此内容的信息。 复制的唯一信息适用于用户和角色。 对于在前面的步骤中创建的项目,将信息复制到用户表的 SQL 查询将是

INSERT INTO AspNetUsers(Id,UserName,PasswordHash,SecurityStamp,EmailConfirmed,
PhoneNumber,PhoneNumberConfirmed,TwoFactorEnabled,LockoutEndDateUtc,LockoutEnabled,AccessFailedCount,
ApplicationId,LoweredUserName,MobileAlias,IsAnonymous,LastActivityDate,LegacyPasswordHash,
MobilePIN,Email,LoweredEmail,PasswordQuestion,PasswordAnswer,IsApproved,IsLockedOut,CreateDate,
LastLoginDate,LastPasswordChangedDate,LastLockoutDate,FailedPasswordAttemptCount,
FailedPasswordAnswerAttemptWindowStart,FailedPasswordAnswerAttemptCount,FailedPasswordAttemptWindowStart,Comment)
SELECT aspnet_Users.UserId,aspnet_Users.UserName,(aspnet_Membership.Password+'|'+CAST(aspnet_Membership.PasswordFormat as varchar)+'|'+aspnet_Membership.PasswordSalt),NewID(),
'true',NULL,'false','true',aspnet_Membership.LastLockoutDate,'true','0',
aspnet_Users.ApplicationId,aspnet_Users.LoweredUserName,
aspnet_Users.MobileAlias,aspnet_Users.IsAnonymous,aspnet_Users.LastActivityDate,aspnet_Membership.Password,
aspnet_Membership.MobilePIN,aspnet_Membership.Email,aspnet_Membership.LoweredEmail,aspnet_Membership.PasswordQuestion,aspnet_Membership.PasswordAnswer,
aspnet_Membership.IsApproved,aspnet_Membership.IsLockedOut,aspnet_Membership.CreateDate,aspnet_Membership.LastLoginDate,aspnet_Membership.LastPasswordChangedDate,
aspnet_Membership.LastLockoutDate,aspnet_Membership.FailedPasswordAttemptCount, aspnet_Membership.FailedPasswordAnswerAttemptWindowStart,
aspnet_Membership.FailedPasswordAnswerAttemptCount,aspnet_Membership.FailedPasswordAttemptWindowStart,aspnet_Membership.Comment
FROM aspnet_Users
LEFT OUTER JOIN aspnet_Membership ON aspnet_Membership.ApplicationId = aspnet_Users.ApplicationId 
AND aspnet_Users.UserId = aspnet_Membership.UserId;

在上述 SQL 语句中,有关 来自aspnet_Usersaspnet_Membership 表的每个用户的信息将复制到 AspnetUsers 表的列中。 此处完成的唯一修改是复制密码时。 由于 SQL 成员身份中的密码加密算法使用了“PasswordSalt”和“PasswordFormat”,因此我们也复制该算法以及哈希密码,以便它可用于通过标识解密密码。 在连接自定义密码 hasher 时,本文进一步介绍了这一点。

此脚本文件特定于此示例。 对于具有其他表的应用程序,开发人员可以遵循类似的方法在用户模型类中添加其他属性,并将其映射到 AspnetUsers 表中的列。 若要运行脚本,

  1. 打开 Server Explorer。 展开“ApplicationServices”连接以显示表。 右键单击“表”节点,然后选择“新建查询”选项

    “打开服务器资源管理器”的屏幕截图,用于展开应用程序服务连接以显示表。

  2. 在查询窗口中,从 Migrations.sql 文件复制并粘贴整个 SQL 脚本。 通过单击“执行”箭头按钮运行脚本文件。

    要复制并粘贴整个 S Q L 脚本的查询窗口的屏幕截图。

    刷新服务器资源管理器窗口。 数据库中创建了五个新表。

    刷新服务器资源管理器窗口以在数据库中创建新表的屏幕截图。

    数据连接中的表的屏幕截图。

    下面是 SQL 成员身份表中的信息如何映射到新的标识系统。

    aspnet_Roles --> AspNetRoles

    asp_netUsers和asp_netMembership --> AspNetUsers

    aspnet_UserInRoles --> AspNetUserRoles

    如上述部分所述,AspNetUserClaims 和 AspNetUserLogins 表为空。 AspNetUser 表中的“歧视性”字段应与定义为下一步的模型类名称匹配。 此外,PasswordHash 列采用“加密密码|password salt|password 格式”。 这样,便可以使用特殊的 SQL 成员身份加密逻辑,以便重复使用旧密码。 本文后面的部分对此进行了说明。

创建模型和成员身份页

如前所述,标识功能使用 Entity Framework 与数据库通信,以便默认存储帐户信息。 若要处理表中的现有数据,我们需要创建模型类,这些类映射回表并在标识系统中将其挂钩。 作为标识协定的一部分,模型类应实现 Identity.Core dll 中定义的接口,也可以扩展 Microsoft.AspNet.Identity.EntityFramework 中可用的这些接口的现有实现。

在我们的示例中,AspNetRoles、AspNetUserClaims、AspNetLogins 和 AspNetUserRole 表具有类似于标识系统现有实现的列。 因此,我们可以重复使用现有类来映射到这些表。 AspNetUser 表具有一些其他列,用于存储 SQL 成员身份表中的其他信息。 可以通过创建扩展现有“IdentityUser”实现并添加其他属性的模型类来映射这一点。

  1. 在项目中创建 Models 文件夹并添加类 User。 类的名称应与“AspnetUsers”表的“歧视性”列中添加的数据匹配。

    在项目中创建 Models 文件夹并添加类 User 的屏幕截图。

    User 类应扩展 Microsoft.AspNet.Identity.EntityFramework dll 中找到的 IdentityUser 类。 在类中声明映射到 AspNetUser 列的属性。 属性 ID、用户名、PasswordHash 和 SecurityStamp 在 IdentityUser 中定义,因此将被省略。 下面是具有所有属性的用户类的代码

    public class User : IdentityUser
    {
        public User()
        {
            CreateDate = DateTime.Now;
            IsApproved = false;
            LastLoginDate = DateTime.Now;
            LastActivityDate = DateTime.Now;
            LastPasswordChangedDate = DateTime.Now;
            LastLockoutDate = DateTime.Parse("1/1/1754");
            FailedPasswordAnswerAttemptWindowStart = DateTime.Parse("1/1/1754");
            FailedPasswordAttemptWindowStart = DateTime.Parse("1/1/1754");
        }
    
        public System.Guid ApplicationId { get; set; }
        public string MobileAlias { get; set; }
        public bool IsAnonymous { get; set; }
        public System.DateTime LastActivityDate { get; set; }
        public string MobilePIN { get; set; }
        public string LoweredEmail { get; set; }
        public string LoweredUserName { get; set; }
        public string PasswordQuestion { get; set; }
        public string PasswordAnswer { get; set; }
        public bool IsApproved { get; set; }
        public bool IsLockedOut { get; set; }
        public System.DateTime CreateDate { get; set; }
        public System.DateTime LastLoginDate { get; set; }
        public System.DateTime LastPasswordChangedDate { get; set; }
        public System.DateTime LastLockoutDate { get; set; }
        public int FailedPasswordAttemptCount { get; set; }
        public System.DateTime FailedPasswordAttemptWindowStart { get; set; }
        public int FailedPasswordAnswerAttemptCount { get; set; }
        public System.DateTime FailedPasswordAnswerAttemptWindowStart { get; set; }
        public string Comment { get; set; }
    }
    
  2. 实体框架 DbContext 类是必需的,以便将数据保存在模型中回到表,并从表中检索数据以填充模型。 Microsoft.AspNet.Identity.EntityFramework dll 定义 IdentityDbContext 类,该类与标识表交互以检索和存储信息。 IdentityDbContext<tuser> 采用“TUser”类,可以是扩展 IdentityUser 类的任何类。

    创建一个新类 ApplicationDBContext,该类在“Models”文件夹下扩展 IdentityDbContext,并传入步骤 1 中创建的“User”类

    public class ApplicationDbContext : IdentityDbContext<User>
    {
            
    }
    
  3. 新标识系统中的用户管理是使用 Microsoft.AspNet.Identity.EntityFramework dll 中定义的 UserManager<tuser> 类完成的。 我们需要创建一个扩展 UserManager 的自定义类,传入步骤 1 中创建的“User”类。

    在 Models 文件夹中,创建扩展 UserManager 用户的新类 UserManager<>

    public class UserManager : UserManager<User>
    {
            
    }
    
  4. 应用程序用户的密码经过加密并存储在数据库中。 SQL 成员身份中使用的加密算法不同于新标识系统中的加密算法。 若要重复使用旧密码,需要在旧用户使用 SQL 成员身份算法登录时选择性地解密密码,同时在新用户的标识中使用加密算法。

    UserManager 类具有属性“PasswordHasher”,用于存储实现“IPasswordHasher”接口的类的实例。 这用于在用户身份验证事务期间加密/解密密码。 在步骤 3 中定义的 UserManager 类中,创建新的类 SQLPasswordHasher 并复制以下代码。

    public class SQLPasswordHasher : PasswordHasher
    {
        public override string HashPassword(string password)
        {
            return base.HashPassword(password);
        }
    
        public override PasswordVerificationResult VerifyHashedPassword(string  hashedPassword, string providedPassword)
        {
            string[] passwordProperties = hashedPassword.Split('|');
            if (passwordProperties.Length != 3)
            {
                return base.VerifyHashedPassword(hashedPassword, providedPassword);
            }
            else
            {
                string passwordHash = passwordProperties[0];
                int passwordformat = 1;
                string salt = passwordProperties[2];
                if (String.Equals(EncryptPassword(providedPassword, passwordformat, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
                {
                    return PasswordVerificationResult.SuccessRehashNeeded;
                }
                else
                {
                    return PasswordVerificationResult.Failed;
                }
            }
        }
    
        //This is copied from the existing SQL providers and is provided only for back-compat.
        private string EncryptPassword(string pass, int passwordFormat, string salt)
        {
            if (passwordFormat == 0) // MembershipPasswordFormat.Clear
                return pass;
    
            byte[] bIn = Encoding.Unicode.GetBytes(pass);
            byte[] bSalt = Convert.FromBase64String(salt);
            byte[] bRet = null;
    
            if (passwordFormat == 1)
            { // MembershipPasswordFormat.Hashed 
                HashAlgorithm hm = HashAlgorithm.Create("SHA1");
                if (hm is KeyedHashAlgorithm)
                {
                    KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
                    if (kha.Key.Length == bSalt.Length)
                    {
                        kha.Key = bSalt;
                    }
                    else if (kha.Key.Length < bSalt.Length)
                    {
                        byte[] bKey = new byte[kha.Key.Length];
                        Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
                        kha.Key = bKey;
                    }
                    else
                    {
                        byte[] bKey = new byte[kha.Key.Length];
                        for (int iter = 0; iter < bKey.Length; )
                        {
                            int len = Math.Min(bSalt.Length, bKey.Length - iter);
                            Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
                            iter += len;
                        }
                        kha.Key = bKey;
                    }
                    bRet = kha.ComputeHash(bIn);
                }
                else
                {
                    byte[] bAll = new byte[bSalt.Length + bIn.Length];
                    Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
                    Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
                    bRet = hm.ComputeHash(bAll);
                }
            }
    
            return Convert.ToBase64String(bRet);
        }
    

    通过导入 System.Text 和 System.Security.Cryptography 命名空间来解决编译错误。

    EncodePassword 方法根据默认 SQL 成员身份加密实现加密密码。 这是从 System.Web dll 获取的。 如果旧应用使用了自定义实现,则应在此处反映它。 我们需要定义其他两种方法 HashPasswordVerifyHashedPassword ,这些方法使用 EncodePassword 方法对给定密码进行哈希,或使用数据库中现有的密码验证纯文本密码。

    SQL 成员身份系统使用 PasswordHash、PasswordSalt 和 PasswordFormat 对用户注册或更改其密码时输入的密码进行哈希处理。 在迁移过程中,所有这三个字段都存储在 AspNetUser 表中的 PasswordHash 列中,用“|”字符分隔。 当用户登录和密码具有这些字段时,我们使用 SQL 成员身份加密来检查密码;否则,我们使用标识系统的默认加密来验证密码。 这样,在迁移应用后,旧用户就不必更改其密码。

  5. 声明 UserManager 类的构造函数,并将其作为 SQLPasswordHasher 传递给构造函数中的属性。

    public UserManager()
                : base(new UserStore<User>(new ApplicationDbContext()))
    {
                this.PasswordHasher = new SQLPasswordHasher();
    }
    

创建新的帐户管理页

迁移的下一步是添加帐户管理页,以便用户注册并登录。 SQL 成员身份中的旧帐户页使用不适用于新标识系统的控件。 若要添加新的用户管理页,请从“将Web Forms添加到应用程序”步骤开始,在此链接https://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-project中添加教程,因为我们已经创建了项目并添加了 NuGet 包。

我们需要对示例进行一些更改,以便处理此处的项目。

  • Register.aspx.cs 和 Login.aspx.cs 代码隐藏类使用 UserManager 标识包中的代码创建用户。 对于此示例,请按照前面所述的步骤使用在 Models 文件夹中添加的 UserManager。

  • 使用在 Register.aspx.cs 和 Login.aspx.cs 代码后面创建的用户类,而不是 IdentityUser。 这将在我们的自定义用户类中挂钩到 Identity 系统。

  • 可以跳过创建数据库的部件。

  • 开发人员需要为新用户设置 ApplicationId 以匹配当前应用程序 ID。 为此,可以在 Register.aspx.cs 类中创建用户对象之前查询此应用程序的 ApplicationId,并在创建用户之前对其进行设置。

    示例:

    在 Register.aspx.cs 页中定义方法以查询aspnet_Applications表,并根据应用程序名称获取应用程序 ID

    private Guid GetApplicationID()
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
        {
            string queryString = "SELECT ApplicationId from aspnet_Applications WHERE ApplicationName = '/'"; //Set application name as in database
    
            SqlCommand command = new SqlCommand(queryString, connection);
            command.Connection.Open();
    
            var reader = command.ExecuteReader();
            while (reader.Read())
            {
                return reader.GetGuid(0);
            }
    
            return Guid.NewGuid();
        }
    }
    

    现在,在用户对象上设置此项

    var currentApplicationId = GetApplicationID();
    
    User user = new User() { UserName = Username.Text,
    ApplicationId=currentApplicationId, …};
    

使用旧用户名和密码登录现有用户。 使用“注册”页创建新用户。 此外,请验证用户是否按预期处于角色。

移植到标识系统有助于用户向应用程序添加开放身份验证 (OAuth) 。 请参阅 此处 已启用 OAuth 的示例。

后续步骤

在本教程中,我们演示了如何将用户从 SQL 成员身份移植到 ASP.NET 标识,但未移植配置文件数据。 在下一教程中,我们将探讨将配置文件数据从 SQL 成员身份移植到新的标识系统。

可以在本文底部留下反馈。

感谢汤姆·迪克斯特拉和里克·安德森审查这篇文章。