Поделиться через


Перенос данных универсального поставщика членства и профилей пользователей в ASP.NET Identity (C#)

Пранав Растоги( Pranav Rastogi),Рик Андерсон (Rick Anderson),Роберт Макмюррей (Robert McMurray),Сухас Джоши (Suhas Joshi)

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

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

В качестве примера мы начнем с веб-приложения, созданного с помощью Visual Studio 2012, в котором используется модель поставщиков. Затем мы добавим код для управления профилями, зарегистрируем пользователя, добавим данные профиля для пользователей, перенесем схему базы данных, а затем изменим приложение для использования системы идентификации для управления пользователями и ролями. В качестве теста миграции пользователи, созданные с помощью универсальные поставщики, должны иметь возможность входа, а новые пользователи должны иметь возможность регистрироваться.

Примечание

Полный пример можно найти на странице https://github.com/suhasj/UniversalProviders-Identity-Migrations.

Сводка по переносу данных профиля

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

  1. Добавьте класс со свойствами, используемыми для хранения данных профиля.
  2. Добавьте класс, расширяющий "ProfileBase" и реализующий методы для получения указанных выше данных профиля для пользователя.
  3. Включите использование поставщиков профилей по умолчанию в файле web.config и определите класс, объявленный на шаге 2, для использования при доступе к данным профиля.

Сведения о профиле хранятся в виде сериализованных xml-данных и двоичных данных в таблице Profiles в базе данных.

После переноса приложения для использования новой системы удостоверений ASP.NET данные профиля десериализируются и сохраняются в качестве свойств в классе пользователя. Затем каждое свойство можно сопоставить со столбцами в пользовательской таблице. Преимущество заключается в том, что над свойствами можно работать напрямую с помощью класса пользователя, а также не требуется каждый раз сериализовать или десериализовать данные при доступе к ним.

Приступая к работе

  1. Создайте новое приложение веб-формы ASP.NET 4.5 в Visual Studio 2012. В текущем примере используется шаблон веб-формы, но можно также использовать приложение MVC.

    Снимок экрана: созданное приложение веб-формы в Visual Studio 2012 с помощью шаблона веб-формы.

  2. Создание папки Models для хранения сведений профиля

    Снимок экрана: новая папка Models, созданная для хранения сведений профиля.

  3. Например, давайте храним дату рождения, город, рост и вес пользователя в профиле. Высота и вес хранятся в виде пользовательского класса с именем "PersonalStats". Чтобы сохранить и получить профиль, нам нужен класс, расширяющий ProfileBase. Давайте создадим класс AppProfile для получения и хранения сведений профиля.

    public class ProfileInfo
    {
        public ProfileInfo()
        {
            UserStats = new PersonalStats();
        }
        public DateTime? DateOfBirth { get; set; }
        public PersonalStats UserStats { get; set; }
        public string City { get; set; }
    }
    
    public class PersonalStats
    {
        public int? Weight { get; set; }
        public int? Height { get; set; }
    }
    
    public class AppProfile : ProfileBase
    {
        public ProfileInfo ProfileInfo
        {
            get { return (ProfileInfo)GetPropertyValue("ProfileInfo"); }
        }
        public static AppProfile GetProfile()
        {
            return (AppProfile)HttpContext.Current.Profile;
        }
        public static AppProfile GetProfile(string userName)
        {
            return (AppProfile)Create(userName);
        }
    }
    
  4. Включите профиль в файлеweb.config . Введите имя класса, который будет использоваться для хранения и извлечения сведений о пользователе, созданных на шаге 3.

    <profile defaultProvider="DefaultProfileProvider" enabled="true"
        inherits="UniversalProviders_ProfileMigrations.Models.AppProfile">
      <providers>
        .....
      </providers>
    </profile>
    
  5. Добавьте страницу веб-форм в папку "Учетная запись", чтобы получить данные профиля от пользователя и сохранить их. Щелкните правой кнопкой мыши проект и выберите "Добавить новый элемент". Добавьте новую страницу веб-форм с master страницей AddProfileData.aspx. Скопируйте следующую команду в разделе MainContent:

    <h2> Add Profile Data for <%# User.Identity.Name %></h2>
    <asp:Label Text="" ID="Result" runat="server" />
    <div>
        Date of Birth:
        <asp:TextBox runat="server" ID="DateOfBirth"/>
    </div>
    <div>
        Weight:
        <asp:TextBox runat="server" ID="Weight"/>
    </div>
    <div>
        Height:
        <asp:TextBox runat="server" ID="Height"/>
    </div>
    <div>
        City:
        <asp:TextBox runat="server" ID="City"/>
    </div>
    <div>
        <asp:Button Text="Add Profile" ID="Add" OnClick="Add_Click" runat="server" />
    </div>
    

    Добавьте следующий код в код программной части:

    protected void Add_Click(object sender, EventArgs e)
    {
        AppProfile profile = AppProfile.GetProfile(User.Identity.Name);
        profile.ProfileInfo.DateOfBirth = DateTime.Parse(DateOfBirth.Text);
        profile.ProfileInfo.UserStats.Weight = Int32.Parse(Weight.Text);
        profile.ProfileInfo.UserStats.Height = Int32.Parse(Height.Text);
        profile.ProfileInfo.City = City.Text;
        profile.Save();
    }
    

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

  6. Запустите приложение и создайте нового пользователя с именем пользователя olduser. Перейдите на страницу AddProfileData и добавьте сведения о профиле пользователя.

    Снимок экрана: страница

Вы можете убедиться, что данные хранятся в виде сериализованного XML-файла в таблице "Профили", с помощью окна Серверная Обозреватель. В Visual Studio в меню "Вид" выберите "Серверная Обозреватель". Должно быть подключение к данным для базы данных, определенной в файлеweb.config . При выборе подключения к данным отображаются различные подкатегории. Разверните "Таблицы", чтобы отобразить различные таблицы в базе данных, а затем щелкните правой кнопкой мыши "Профили" и выберите "Показать данные таблицы", чтобы просмотреть данные профиля, хранящиеся в таблице Profiles.

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

Снимок экрана: таблица данных Profiles.

Перенос схемы базы данных

Чтобы существующая база данных работала с системой удостоверений, необходимо обновить схему в базе данных Identity для поддержки полей, добавленных в исходную базу данных. Это можно сделать с помощью скриптов SQL для создания таблиц и копирования существующих сведений. В окне Server Обозреватель разверните defaultConnection, чтобы отобразить таблицы. Щелкните правой кнопкой мыши Таблицы и выберите "Новый запрос".

Снимок экрана: обновление схемы в базе данных удостоверений с помощью кнопки Создать запрос.

Вставьте скрипт SQL из https://raw.github.com/suhasj/UniversalProviders-Identity-Migrations/master/Migration.txt и запустите его. Если параметр DefaultConnection обновлен, мы видим, что добавлены новые таблицы. Вы можете проверка данные в таблицах, чтобы убедиться, что информация была перенесена.

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

Перенос приложения для использования ASP.NET Identity

  1. Установите пакеты NuGet, необходимые для ASP.NET Identity:

    • Microsoft.AspNet.Identity.EntityFramework
    • 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 можно найти здесь.

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

    using Microsoft.AspNet.Identity.EntityFramework;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using UniversalProviders_ProfileMigrations.Models;
    
    namespace UniversalProviders_Identity_Migrations
    {
        public class User : IdentityUser
        {
            public User()
            {
                CreateDate = DateTime.UtcNow;
                IsApproved = false;
                LastLoginDate = DateTime.UtcNow;
                LastActivityDate = DateTime.UtcNow;
                LastPasswordChangedDate = DateTime.UtcNow;
                Profile = new ProfileInfo();
            }
    
            public System.Guid ApplicationId { get; set; }
            public bool IsAnonymous { get; set; }
            public System.DateTime? LastActivityDate { get; set; }
            public string Email { 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; }
            public ProfileInfo Profile { get; set; }
        }
    }
    

    Обратите внимание, что ProfileInfo теперь является свойством класса пользователя. Поэтому мы можем использовать класс пользователя для непосредственной работы с данными профиля.

Скопируйте файлы в папках IdentityModels и IdentityAccount из источника загрузки ( https://github.com/suhasj/UniversalProviders-Identity-Migrations/tree/master/UniversalProviders-Identity-Migrations ). Они имеют оставшиеся классы моделей и новые страницы, необходимые для управления пользователями и ролями с помощью API ASP.NET Identity. Используемый подход аналогичен членству в SQL, и подробное объяснение можно найти здесь.

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

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

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

Копирование данных профиля в новые таблицы

Как упоминалось ранее, необходимо выполнить десериализацию xml-данных в таблицах Profiles и сохранить их в столбцах таблицы AspNetUsers. Новые столбцы были созданы в таблице users на предыдущем шаге, поэтому осталось только заполнить эти столбцы необходимыми данными. Для этого мы будем использовать консольное приложение, которое запускается один раз для заполнения только что созданных столбцов в таблице users.

  1. Создайте консольное приложение в выходе из решения.

    Снимок экрана: создание консольного приложения в выходе из решения.

  2. Установите последнюю версию пакета Entity Framework.

  3. Добавьте созданное выше веб-приложение в качестве ссылки на консольное приложение. Для этого щелкните правой кнопкой мыши проект, затем "Добавить ссылки", затем Решение, а затем щелкните проект и нажмите кнопку ОК.

  4. Скопируйте приведенный ниже код в класс Program.cs. Эта логика считывает данные профиля для каждого пользователя, сериализует их как объект ProfileInfo и сохраняет обратно в базу данных.

    public class Program
    {
        var dbContext = new ApplicationDbContext();
        foreach (var profile in dbContext.Profiles)
        {
            var stringId = profile.UserId.ToString();
            var user = dbContext.Users.Where(x => x.Id == stringId).FirstOrDefault();
            Console.WriteLine("Adding Profile for user:" + user.UserName);
            var serializer = new XmlSerializer(typeof(ProfileInfo));
            var stringReader = new StringReader(profile.PropertyValueStrings);
            var profileData = serializer.Deserialize(stringReader) as ProfileInfo;
            if (profileData == null)
            {
                Console.WriteLine("Profile data deserialization error for user:" + user.UserName);
            }
            else
            {
                user.Profile = profileData;
            }
        }
        dbContext.SaveChanges();
    }
    

    Некоторые из используемых моделей определяются в папке IdentityModels проекта веб-приложения, поэтому необходимо включить соответствующие пространства имен.

  5. Приведенный выше код работает с файлом базы данных в папке App_Data проекта веб-приложения, созданного на предыдущих шагах. Чтобы сослаться на это, обновите строку подключения в файле app.config консольного приложения, указав строку подключения в web.config веб-приложения. Также укажите полный физический путь в свойстве AttachDbFilename.

  6. Откройте командную строку и перейдите в папку bin указанного выше консольного приложения. Запустите исполняемый файл и просмотрите выходные данные журнала, как показано на следующем рисунке.

    Снимок экрана: исполняемый файл в командной строке для запуска и просмотра выходных данных журнала.

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

Проверка функциональности

Используйте только что добавленные страницы членства, реализованные с помощью ASP.NET Identity, для входа пользователя из старой базы данных. Пользователь должен иметь возможность войти в систему с теми же учетными данными. Попробуйте использовать другие функции, такие как добавление OAuth, создание нового пользователя, изменение пароля, добавление ролей, добавление пользователей к ролям и т. д.

Данные профиля для старого и нового пользователей должны быть извлечены и сохранены в таблице users. На старую таблицу больше не следует ссылаться.

Заключение

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

Спасибо Рику Андерсону и Роберту Мак-Мюррейу за просмотр статьи.