Миграция существующего веб-сайта из членства SQL в ASP.NET Identity

Рик Андерсон( Rick Anderson), Сухас Джоши (Suhas Joshi)

В этом руководстве показано, как перенести существующее веб-приложение с данными пользователей и ролей, созданными с помощью членства SQL, в новую систему ASP.NET Identity. Этот подход включает в себя изменение существующей схемы базы данных на ту, которая необходима для ASP.NET Identity и перехватчика в старых или новых классах. После того как вы примете этот подход, после переноса базы данных будущие обновления identity будут обрабатываться без особых усилий.

В этом руководстве мы рассмотрим шаблон веб-приложения (веб-формы), созданный с помощью Visual Studio 2010 для создания данных пользователей и ролей. Затем мы будем использовать скрипты SQL для переноса существующей базы данных в таблицы, необходимые системе удостоверений. Далее мы установим необходимые пакеты NuGet и добавим новые страницы управления учетными записями, которые используют систему удостоверений для управления членством. В качестве теста миграции пользователи, созданные с помощью членства SQL, должны иметь возможность входа, а новые пользователи должны иметь возможность регистрироваться. Полный пример см. здесь. См. также раздел Переход с ASP.NET членства на ASP.NET identity.

Начало работы

Создание приложения с членством в SQL

  1. Мы должны начать с существующего приложения, которое использует членство SQL и имеет данные пользователей и ролей. В этой статье мы создадим веб-приложение в Visual Studio 2010.

    Снимок экрана: создание веб-приложения в Visual Studio 2010.

  2. С помощью средства настройки ASP.NET создайте двух пользователей: oldAdminUser и oldUser.

    Снимок экрана: 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 identity.

    Снимок экрана: серверная Обозреватель для просмотра базы данных, чтобы понять таблицы, созданные системой членства S Q L.

Переход на Visual Studio 2013

  1. Установите Visual Studio Express 2013 для web или Visual Studio 2013 вместе с последними обновлениями.

  2. Откройте указанный выше проект в установленной версии Visual Studio. Если SQL Server Express не установлен на компьютере, при открытии проекта отображается запрос, так как строка подключения использует SQL Express. Вы можете установить SQL Express или изменить строку подключения на LocalDb. В этой статье мы изменим его на LocalDb.

  3. Откройте web.config и измените строку подключения с . SQLExpress в (LocalDb)версии 11.0. Удалите user instance=true из строки подключения.

    Снимок экрана: изменение строки подключения для миграции на Visual Studio 2013.

  4. Откройте серверный Обозреватель и убедитесь, что схема таблицы и данные можно наблюдать.

  5. Система ASP.NET Identity работает с платформой версии 4.5 или более поздней. Перенацеливать приложение на версию 4.5 или выше.

    Снимок экрана: A S P . Система удостоверений N E T.

    Выполните сборку проекта, чтобы убедиться в отсутствии ошибок.

Установка пакетов NuGet

  1. В Обозреватель решений щелкните правой кнопкой мыши проект >Управление пакетами NuGet. В поле поиска введите "Asp.net Identity". Выберите пакет в списке результатов и нажмите кнопку Установить. Примите лицензионное соглашение, нажав кнопку "Принимаю". Обратите внимание, что этот пакет установит пакеты зависимостей: EntityFramework и Microsoft ASP.NET Identity Core. Аналогичным образом установите следующие пакеты (пропустите последние 4 пакета OWIN, если вы не хотите включать вход OAuth):

    • Microsoft.AspNet.Identity.Owin

    • Microsoft.Owin.Host.SystemWeb

    • Microsoft.Owin.Security.Facebook

    • Microsoft.Owin.Security.Google

    • Microsoft.Owin.Security.MicrosoftAccount

    • Microsoft.Owin.Security.Twitter

      Снимок экрана: установка пакетов Nuget в Обозреватель решений.

Перенос базы данных в новую систему удостоверений

Следующим шагом является перенос существующей базы данных в схему, необходимую для системы ASP.NET Identity. Для этого мы запускаем скрипт SQL, который содержит набор команд для создания новых таблиц и переноса существующих сведений о пользователях в новые таблицы. Файл скрипта можно найти здесь.

Этот файл скрипта предназначен только для этого примера. Если схема для таблиц, созданных с использованием членства SQL, настроена или изменена, скрипты необходимо соответствующим образом изменить.

Создание скрипта SQL для миграции схемы

Чтобы классы ASP.NET Identity работали с данными существующих пользователей, необходимо перенести схему базы данных в схему, необходимую для ASP.NET Identity. Это можно сделать, добавив новые таблицы и скопировав в них существующие сведения. По умолчанию ASP.NET Identity использует EntityFramework для сопоставления классов модели удостоверений с базой данных для хранения и извлечения информации. Эти классы моделей реализуют основные интерфейсы identity, определяющие объекты пользователей и ролей. Таблицы и столбцы в базе данных основаны на этих классах моделей. Классы модели EntityFramework в Identity версии 2.1.0 и их свойства приведены ниже.

IdentityUser Тип IdentityRole IdentityUserRole IdentityUserLogin IdentityUserClaim
Идентификатор строка Идентификатор RoleId ProviderKey Идентификатор
Имя пользователя строка Имя UserId UserId ClaimType
PasswordHash строка LoginProvider ClaimValue
SecurityStamp строка User_Id
Адрес электронной почты строка
EmailConfirmed bool
PhoneNumber строка
PhoneNumberConfirmed bool
LockoutEnabled bool
LockoutEndDate Дата и время
AccessFailedCount INT

Для каждой из этих моделей необходимо иметь таблицы со столбцами, соответствующими свойствам. Сопоставление между классами и таблицами определяется в OnModelCreating методе IdentityDBContext. Это называется текучим методом настройки API. Дополнительные сведения можно найти здесь. Конфигурация для классов, как описано ниже

Класс Таблица Главный ключ Внешний ключ
IdentityUser AspnetUsers Идентификатор
IdentityRole AspnetRoles Идентификатор
IdentityUserRole AspnetUserRole UserId + RoleId User_Id-AspnetUsers> RoleId-AspnetRoles>
IdentityUserLogin AspnetUserLogins ProviderKey+UserId +LoginProvider UserId-AspnetUsers>
IdentityUserClaim AspnetUserClaims Идентификатор User_Id-AspnetUsers>

С помощью этих сведений можно создавать инструкции SQL для создания новых таблиц. Мы можем написать каждую инструкцию по отдельности или создать весь скрипт с помощью команд PowerShell EntityFramework, которые затем можно изменить по мере необходимости. Для этого в VS откройте консоль диспетчера пакетов в меню Вид или Сервис .

  • Выполните команду Enable-Migrations, чтобы включить миграцию EntityFramework.
  • Выполните команду Add-migration initial, которая создает код начальной установки для создания базы данных в C#/VB.
  • Последним шагом является выполнение команды Update-Database –Script, которая создает скрипт SQL на основе классов модели.

Некоторые команды не поддерживаются, если приложение использует SQLite в качестве хранилища данных удостоверений. Из-за ограничений в ядре СУБД Alter команды вызывают следующее исключение:

"System.NotSupportedException: SQLite не поддерживает эту операцию миграции".

В качестве обходного решения выполните миграцию Code First в базе данных, чтобы изменить таблицы.

Этот скрипт создания базы данных можно использовать в качестве начала, где мы будем вносить дополнительные изменения для добавления новых столбцов и копирования данных. Преимуществом этого является то, что мы создаем таблицу _MigrationHistory , которая используется EntityFramework для изменения схемы базы данных при изменении классов моделей для будущих версий удостоверений.

В дополнение к свойствам в классе пользовательской модели удостоверений у сведений о членстве в SQL были другие свойства, а именно электронная почта, попытки ввода пароля, дата последнего входа, последняя дата блокировки и т. д. Это полезная информация, и мы хотели бы, чтобы она была перенесена в систему удостоверений. Это можно сделать, добавив дополнительные свойства к пользовательской модели и сопоставив их со столбцами таблицы в базе данных. Это можно сделать, добавив класс, который является подклассом IdentityUser модели. Мы можем добавить свойства в этот пользовательский класс и изменить скрипт SQL, чтобы добавить соответствующие столбцы при создании таблицы. Код для этого класса описан далее в статье. Скрипт SQL для создания AspnetUsers таблицы после добавления новых свойств будет

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 в только что добавленные таблицы для Identity. Это можно сделать с помощью SQL, скопировав данные непосредственно из одной таблицы в другую. Чтобы добавить данные в строки таблицы, мы используем конструкцию INSERT INTO [Table] . Для копирования из другой таблицы можно использовать INSERT INTO оператор вместе с оператором SELECT . Чтобы получить все сведения о пользователях, необходимо запросить таблицы aspnet_Users и aspnet_Membership и скопировать данные в таблицу AspNetUsers . Мы используем INSERT INTO и SELECT вместе с операторами JOIN и LEFT 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_Users и aspnet_Membership копируются в столбцы таблицы AspnetUsers . Единственное изменение выполняется при копировании пароля. Так как алгоритм шифрования паролей в членстве SQL использует "PasswordSalt" и "PasswordFormat", мы копируем их вместе с хэш-паролем, чтобы его можно было использовать для расшифровки пароля по идентификатору. Это объясняется далее в статье при подключении пользовательского хэшера паролей.

Этот файл скрипта предназначен только для этого примера. Для приложений с дополнительными таблицами разработчики могут следовать аналогичному подходу, чтобы добавить дополнительные свойства в класс пользовательской модели и сопоставить их со столбцами в таблице AspnetUsers. Чтобы запустить скрипт, выполните следующие действия:

  1. Откройте обозреватель сервера. Разверните подключение ApplicationServices, чтобы отобразить таблицы. Щелкните правой кнопкой мыши узел Таблицы и выберите параметр "Новый запрос".

    Снимок экрана: Обозреватель Open Server для развертывания подключения к службам приложений для отображения таблиц.

  2. В окне запроса скопируйте и вставьте весь скрипт SQL из файла Migrations.sql. Запустите файл скрипта, нажав кнопку со стрелкой "Выполнить".

    Снимок экрана: окно запроса для копирования и вставки всего скрипта S Q L.

    Обновите окно Серверная Обозреватель. В базе данных создаются пять новых таблиц.

    Снимок экрана: обновление окна Обозреватель сервера для создания пяти новых таблиц в базе данных.

    Снимок экрана: таблицы в подключениях к данным.

    Ниже показано, как сведения в таблицах членства SQL сопоставляются с новой системой удостоверений.

    aspnet_Roles —> AspNetRoles

    asp_netUsers и asp_netMembership —> AspNetUsers

    aspnet_UserInRoles —> AspNetUserRoles

    Как описано в приведенном выше разделе, таблицы AspNetUserClaims и AspNetUserLogins пусты. Поле "Дискриминатор" в таблице AspNetUser должно соответствовать имени класса модели, которое определяется как следующий шаг. Кроме того, столбец PasswordHash имеет вид "зашифрованный пароль |пароль|пароль в формате". Это позволяет использовать специальную логику шифрования членства SQL, чтобы можно было повторно использовать старые пароли. Это объясняется далее в этой статье.

Создание моделей и страниц членства

Как упоминалось ранее, функция идентификации использует Entity Framework для взаимодействия с базой данных для хранения сведений об учетной записи по умолчанию. Для работы с существующими данными в таблице необходимо создать классы моделей, которые сопоставляются с таблицами и подключить их в системе удостоверений. В рамках контракта Identity классы моделей должны либо реализовывать интерфейсы, определенные в библиотеке DLL Identity.Core, либо расширять существующую реализацию этих интерфейсов, доступных в Microsoft.AspNet.Identity.EntityFramework.

В нашем примере таблицы AspNetRoles, AspNetUserClaims, AspNetLogins и AspNetUserRole содержат столбцы, аналогичные существующей реализации системы удостоверений. Поэтому мы можем повторно использовать существующие классы для сопоставления с этими таблицами. Таблица AspNetUser содержит несколько дополнительных столбцов, которые используются для хранения дополнительных сведений из таблиц членства SQL. Это можно сопоставить, создав класс модели, который расширяет существующую реализацию IdentityUser и добавляет дополнительные свойства.

  1. Создайте папку Models в проекте и добавьте класс User. Имя класса должно соответствовать данным, добавленным в столбец "Дискриминатор" таблицы AspnetUsers.

    Снимок экрана: создание папки Models в проекте и добавление класса User.

    Класс User должен расширить класс IdentityUser, найденный в библиотеке DLL Microsoft.AspNet.Identity.EntityFramework . Объявите свойства в классе , которые сопоставляют со столбцами AspNetUser. Свойства ID, Username, PasswordHash и SecurityStamp определяются в IdentityUser и поэтому опущены. Ниже приведен код для класса User со всеми свойствами.

    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. Класс Entity Framework DbContext необходим для сохранения данных в моделях обратно в таблицы и извлечения данных из таблиц для заполнения моделей. Библиотека DLL Microsoft.AspNet.Identity.EntityFramework определяет класс IdentityDbContext, который взаимодействует с таблицами Identity для получения и хранения информации. Tuser> IdentityDbContext<принимает класс TUser, который может быть любым классом, расширяющим класс IdentityUser.

    Создайте класс ApplicationDBContext, расширяющий IdentityDbContext в папке Models, передав класс User, созданный на шаге 1.

    public class ApplicationDbContext : IdentityDbContext<User>
    {
            
    }
    
  3. Управление пользователями в новой системе удостоверений осуществляется с помощью класса Tuser> UserManager<, определенного в библиотеке DLL Microsoft.AspNet.Identity.EntityFramework. Нам нужно создать пользовательский класс, расширяющий UserManager, передав класс User, созданный на шаге 1.

    В папке Models создайте класс UserManager, расширяющий пользователя UserManager<.>

    public class UserManager : UserManager<User>
    {
            
    }
    
  4. Пароли пользователей приложения шифруются и хранятся в базе данных. Алгоритм шифрования, используемый при членстве в SQL, отличается от алгоритма в новой системе удостоверений. Для повторного использования старых паролей необходимо выборочно расшифровать пароли, когда старые пользователи входят в систему с помощью алгоритма членства в SQL при использовании алгоритма шифрования в identity для новых пользователей.

    Класс UserManager имеет свойство PasswordHasher, в котором хранится экземпляр класса, реализующего интерфейс IPasswordHasher. Используется для шифрования и расшифровки паролей во время транзакций проверки подлинности пользователей. В классе UserManager, определенном на шаге 3, создайте класс 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 по умолчанию. Это взято из библиотеки DLL System.Web. Если старое приложение использовало пользовательскую реализацию, это должно быть отражено здесь. Нам нужно определить два других метода HashPassword и VerifyHashedPassword , которые используют метод EncodePassword для хэширования заданного пароля или проверки пароля в виде обычного текста, имеющегося в базе данных.

    Система членства SQL использовала PasswordHash, PasswordSalt и PasswordFormat для хэширования пароля, введенного пользователями при регистрации или изменении пароля. Во время миграции все три поля хранятся в столбце PasswordHash в таблице AspNetUser, разделенном символом "|". Когда пользователь входит в систему и пароль содержит эти поля, мы используем криптографию членства SQL для проверка пароля; в противном случае мы используем криптографию системы удостоверений по умолчанию для проверки пароля. Таким образом, старым пользователям не придется менять пароли после переноса приложения.

  5. Объявите конструктор для класса UserManager и передайте его как SQLPasswordHasher свойству в конструкторе.

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

Создание страниц управления учетными записями

Следующим шагом миграции является добавление страниц управления учетными записями, которые позволят пользователю зарегистрироваться и войти в систему. Старые страницы учетных записей из членства в SQL используют элементы управления, которые не работают с новой системой удостоверений. Чтобы добавить новые страницы управления пользователями, следуйте инструкциям по этой ссылке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 из пакетов удостоверений для создания пользователя. В этом примере используйте UserManager, добавленный в папку Models, выполнив описанные ранее действия.

  • Используйте класс User, созданный вместо IdentityUser в классах Register.aspx.cs и login.aspx.cs. Это перехватывает наш пользовательский класс в системе удостоверений.

  • Часть для создания базы данных можно пропустить.

  • Разработчику необходимо задать Идентификатор приложения, чтобы новый пользователь соответствовал текущему идентификатору приложения. Это можно сделать, запросив ApplicationId для этого приложения перед созданием объекта пользователя в классе Register.aspx.cs и задав его перед созданием пользователя.

    Пример

    Определите метод на странице Register.aspx.cs для запроса aspnet_Applications таблицы и получения идентификатора приложения в соответствии с именем приложения.

    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.

Next Steps

В этом руководстве мы показали, как перенести пользователей из членства SQL в ASP.NET identity, но не переносить данные профиля. В следующем руководстве мы рассмотрим перенос данных профиля из членства SQL в новую систему удостоверений.

Вы можете оставить отзыв в нижней части этой статьи.

Благодарим Тома Дайкстра и Рика Андерсона за просмотр статьи.