Пользовательские поставщики хранилища для ASP.NET Core Identity
Автор: Стив Смит (Steve Smith)
ASP.NET Core Identity — это расширяемая система, которая позволяет создавать настраиваемый поставщик хранилища и подключать его к приложению. В этом разделе описывается создание настраиваемого поставщика хранилища для ASP.NET Core Identity. В ней рассматриваются важные понятия для создания собственного поставщика хранилища, но это не пошаговые инструкции. Сведения о настройке модели см. в Identity разделе Identity "Настройка модели".
Введение
По умолчанию система ASP.NET Core Identity хранит сведения о пользователе в базе данных SQL Server с помощью Entity Framework Core. Для многих приложений этот подход хорошо работает. Однако вы можете использовать другой механизм сохраняемости или схему данных. Например:
- Вы используете таблицу Azure служба хранилища или другое хранилище данных.
- Таблицы базы данных имеют другую структуру.
- Возможно, вы хотите использовать другой подход к доступу к данным, например Dapper.
В каждом из этих случаев можно написать настраиваемый поставщик для механизма хранения и подключить этого поставщика к приложению.
ASP.NET Core Identity входит в шаблоны проектов в Visual Studio с параметром "Отдельные учетные записи пользователей".
При использовании интерфейса командной строки .NET Core добавьте -au Individual
:
dotnet new mvc -au Individual
Архитектура ядра ASP.NET Identity
ASP.NET Core Identity состоит из классов, называемых менеджерами и магазинами. Руководители — это высокоуровневые классы , которые разработчик приложений использует для выполнения операций, таких как создание Identity пользователя. Хранилища — это классы более низкого уровня, определяющие способ сохранения сущностей, таких как пользователи и роли. Магазины следуют шаблону репозитория и тесно связаны с механизмом сохраняемости. Диспетчеры отделены от магазинов, что означает, что можно заменить механизм сохраняемости без изменения кода приложения (за исключением конфигурации).
На следующей схеме показано, как веб-приложение взаимодействует с руководителями, а хранилища взаимодействуют с уровнем доступа к данным.
Чтобы создать настраиваемый поставщик хранилища, создайте источник данных, уровень доступа к данным и классы хранилища, взаимодействующие с этим уровнем доступа к данным (зеленые и серые поля на схеме выше). Вам не нужно настраивать диспетчеры или код приложения, взаимодействующие с ними (синие поля выше).
При создании нового экземпляра UserManager
или RoleManager
укажите тип пользовательского класса и передайте экземпляр класса store в качестве аргумента. Этот подход позволяет подключать настраиваемые классы к ASP.NET Core.
Перенастройка приложения для использования нового поставщика хранилища показывает, как создать экземпляр UserManager
и RoleManager
с помощью настраиваемого хранилища.
ASP.NET Core Identity хранит типы данных
ASP.NET основные Identity типы данных подробно описаны в следующих разделах:
Пользователи
Зарегистрированные пользователи веб-сайта. Тип IdentityUser может быть расширен или использован в качестве примера для собственного пользовательского типа. Вам не нужно наследовать от определенного типа для реализации собственного решения хранилища удостоверений.
Утверждения пользователей
Набор инструкций (или утверждений) о пользователе, представляющего удостоверение пользователя. Может включить большее выражение удостоверения пользователя, чем можно достичь с помощью ролей.
Имена входа пользователей
Сведения о внешнем поставщике проверки подлинности (например, Facebook или учетной записи Майкрософт) для использования при входе в систему пользователя. Пример
Роли
Группы авторизации для сайта. Включает идентификатор роли и имя роли (например, "Администратор" или "Сотрудник"). Пример
Уровень доступа к данным
В этом разделе предполагается, что вы знакомы с механизмом сохраняемости, используемым и как создавать сущности для этого механизма. В этом разделе не содержатся сведения о создании репозиториев или классов доступа к данным; Он предоставляет некоторые предложения по проектированию решений при работе с ASP.NET Core Identity.
При проектировании уровня доступа к данным для настраиваемого поставщика хранилища у вас много свободы. Необходимо создать только механизмы сохраняемости для функций, которые вы планируете использовать в приложении. Например, если вы не используете роли в приложении, вам не нужно создавать хранилище для ролей или связей ролей пользователей. Для вашей технологии и существующей инфраструктуры может потребоваться структура, которая отличается от реализации по умолчанию ASP.NET Core Identity. На уровне доступа к данным вы предоставляете логику для работы со структурой реализации хранилища.
Уровень доступа к данным предоставляет логику для сохранения данных из ASP.NET Core Identity в источник данных. Уровень доступа к данным для настраиваемого поставщика хранилища может включать следующие классы для хранения сведений о пользователе и роли.
Context - класс
Инкапсулирует сведения для подключения к механизму сохраняемости и выполнения запросов. Для нескольких классов данных требуется экземпляр этого класса, который обычно предоставляется путем внедрения зависимостей. Пример.
Служба хранилища пользователя
Хранит и извлекает сведения о пользователе (например, имя пользователя и хэш паролей). Пример
Роль служба хранилища
Хранит и извлекает сведения о роли (например, имя роли). Пример
Служба хранилища UserClaims
Хранит и извлекает сведения о утверждении пользователя (например, тип утверждения и значение). Пример
Служба хранилища UserLogins
Хранит и извлекает сведения о входе пользователя (например, внешний поставщик проверки подлинности). Пример
UserRole служба хранилища
Хранит и извлекает роли, которым назначены пользователи. Пример
СОВЕТ. Реализуйте только классы, которые вы планируете использовать в приложении.
В классах доступа к данным предоставьте код для выполнения операций с данными для механизма сохраняемости. Например, в пользовательском поставщике может потребоваться следующий код для создания нового пользователя в классе хранилища :
public async Task<IdentityResult> CreateAsync(ApplicationUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null) throw new ArgumentNullException(nameof(user));
return await _usersTable.CreateAsync(user);
}
Логика реализации для создания пользователя находится в методе, показанном _usersTable.CreateAsync
ниже.
Настройка класса пользователя
При реализации поставщика хранилища создайте класс пользователя, эквивалентный классу IdentityUser.
Как минимум, класс пользователя должен включать и Id
UserName
свойство.
Класс IdentityUser
определяет свойства, которые UserManager
вызываются при выполнении запрошенных операций. Тип Id
свойства по умолчанию является строкой, но можно наследовать от IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
другого типа. Платформа ожидает, что реализация хранилища будет обрабатывать преобразования типов данных.
Настройка хранилища пользователей
UserStore
Создайте класс, предоставляющий методы для всех операций с данными пользователя. Этот класс эквивалентен классу UserStore<TUser> . UserStore
В классе реализуйте IUserStore<TUser>
и необязательные интерфейсы. Вы выбираете необязательные интерфейсы для реализации на основе функциональных возможностей, предоставленных в приложении.
Необязательные интерфейсы
- IUserRoleStore
- IUserClaimStore
- IUserPasswordStore
- IUserSecurityStampStore
- IUserEmailStore
- IUser Телефон NumberStore
- IQueryableUserStore
- IUserLoginStore
- IUserTwoFactorStore
- IUserLockoutStore
Необязательные интерфейсы наследуются от IUserStore<TUser>
. В примере приложения можно увидеть частично реализованное образец хранилища пользователей.
UserStore
В классе используются классы доступа к данным, созданные для выполнения операций. Они передаются при использовании внедрения зависимостей. Например, в SQL Server с реализацией Dapper класс имеет CreateAsync
метод, UserStore
который использует экземпляр DapperUsersTable
для вставки новой записи:
public async Task<IdentityResult> CreateAsync(ApplicationUser user)
{
string sql = "INSERT INTO dbo.CustomUser " +
"VALUES (@id, @Email, @EmailConfirmed, @PasswordHash, @UserName)";
int rows = await _connection.ExecuteAsync(sql, new { user.Id, user.Email, user.EmailConfirmed, user.PasswordHash, user.UserName });
if(rows > 0)
{
return IdentityResult.Success;
}
return IdentityResult.Failed(new IdentityError { Description = $"Could not insert user {user.Email}." });
}
Интерфейсы для реализации при настройке пользовательского хранилища
- IUserStore
Интерфейс IUserStore<TUser> является единственным интерфейсом, который необходимо реализовать в пользовательском хранилище. Он определяет методы для создания, обновления, удаления и извлечения пользователей. - IUserClaimStore
Интерфейс IUserClaimStore<TUser> определяет методы, которые вы реализуете для включения утверждений пользователей. Он содержит методы для добавления, удаления и получения утверждений пользователей. - IUserLoginStore
Определяет IUserLoginStore<TUser> методы, которые вы реализуете для включения внешних поставщиков проверки подлинности. Он содержит методы для добавления, удаления и получения имен входа пользователей, а также метода получения пользователя на основе сведений о входе. - IUserRoleStore
Интерфейс IUserRoleStore<TUser> определяет методы, которые вы реализуете для сопоставления пользователя с ролью. Он содержит методы для добавления, удаления и извлечения ролей пользователя, а также метода проверка, если пользователю назначена роль. - IUserPasswordStore
Интерфейс IUserPasswordStore<TUser> определяет методы, которые вы реализуете для сохранения хэшированных паролей. Он содержит методы для получения и настройки хэшированного пароля, а также метод, указывающий, задан ли пользователь пароль. - IUserSecurityStampStore
Интерфейс IUserSecurityStampStore<TUser> определяет методы, которые вы реализуете для использования метки безопасности для указания того, изменились ли сведения учетной записи пользователя. Эта метка обновляется при изменении пароля или добавлении или удалении имен входа. Он содержит методы для получения и настройки метки безопасности. - IUserTwoFactorStore
Интерфейс IUserTwoFactorStore<TUser> определяет методы, которые вы реализуете для поддержки двухфакторной проверки подлинности. Он содержит методы получения и настройки включения двухфакторной проверки подлинности для пользователя. - IUser Телефон NumberStore
Интерфейс IUserPhoneNumberStore<TUser> определяет методы, которые вы реализуете для хранения номеров телефонов пользователей. Он содержит методы для получения и настройки номера телефона и подтверждения номера телефона. - IUserEmailStore
Интерфейс IUserEmailStore<TUser> определяет методы, которые вы реализуете для хранения адресов электронной почты пользователей. Он содержит методы для получения и настройки адреса электронной почты и подтверждения электронной почты. - IUserLockoutStore
Интерфейс IUserLockoutStore<TUser> определяет методы, которые вы реализуете для хранения сведений о блокировке учетной записи. Он содержит методы отслеживания неудачных попыток доступа и блокировки. - IQueryableUserStore
Интерфейс IQueryableUserStore<TUser> определяет элементы, которые вы реализуете для предоставления запрашиваемого хранилища пользователей.
Вы реализуете только интерфейсы, необходимые в приложении. Например:
public class UserStore : IUserStore<IdentityUser>,
IUserClaimStore<IdentityUser>,
IUserLoginStore<IdentityUser>,
IUserRoleStore<IdentityUser>,
IUserPasswordStore<IdentityUser>,
IUserSecurityStampStore<IdentityUser>
{
// interface implementations not shown
}
IdentityUserClaim, IdentityUserLogin и IdentityUserRole
Пространство Microsoft.AspNet.Identity.EntityFramework
имен содержит реализацииIdentity классов UserClaim IdentityUserLoginи IdentityUserRole. Если вы используете эти функции, вам может потребоваться создать собственные версии этих классов и определить свойства для приложения. Однако иногда это более эффективно, чтобы не загружать эти сущности в память при выполнении основных операций (таких как добавление или удаление утверждения пользователя). Вместо этого классы внутреннего хранилища могут выполнять эти операции непосредственно в источнике данных. Например, UserStore.GetClaimsAsync
метод может вызывать userClaimTable.FindByUserId(user.Id)
метод для выполнения запроса в этой таблице напрямую и возвращать список утверждений.
Настройка класса роли
При реализации поставщика хранилища ролей можно создать пользовательский тип роли. Он не должен реализовывать конкретный интерфейс, но он должен иметь свойство, и обычно оно будет иметь Id
Name
свойство.
Ниже приведен пример класса роли:
using System;
namespace CustomIdentityProviderSample.CustomProvider
{
public class ApplicationRole
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
}
}
Настройка хранилища ролей
Можно создать RoleStore
класс, предоставляющий методы для всех операций с данными ролей. Этот класс эквивалентен классу RoleStore<TRole> . RoleStore
В классе реализуется IRoleStore<TRole>
и при необходимости интерфейсIQueryableRoleStore<TRole>
.
- IRoleStore<TRole>
Интерфейс IRoleStore<TRole> определяет методы для реализации в классе хранилища ролей. Он содержит методы для создания, обновления, удаления и извлечения ролей. - RoleStore<TRole>
Чтобы настроитьRoleStore
, создайте класс, реализующийIRoleStore<TRole>
интерфейс.
Перенастройка приложения для использования нового поставщика хранилища
После реализации поставщика хранилища вы настроите приложение для его использования. Если приложение использовало поставщик по умолчанию, замените его пользовательским поставщиком.
Microsoft.AspNetCore.EntityFramework.Identity
Удалите пакет NuGet.- Если поставщик хранилища находится в отдельном проекте или пакете, добавьте в него ссылку.
- Замените все ссылки на
Microsoft.AspNetCore.EntityFramework.Identity
инструкцию using для пространства имен поставщика хранилища. - Измените метод, чтобы использовать пользовательские
AddIdentity
типы. Для этого можно создать собственные методы расширения. Пример см Identity. в разделе ServiceCollectionExtensions . - При использовании ролей обновите
RoleManager
RoleStore
класс. - Обновите строка подключения и учетные данные в конфигурации приложения.
Пример:
public void ConfigureServices(IServiceCollection services)
{
// Add identity types
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddDefaultTokenProviders();
// Identity Services
services.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();
string connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddTransient<SqlConnection>(e => new SqlConnection(connectionString));
services.AddTransient<DapperUsersTable>();
// additional configuration
}
var builder = WebApplication.CreateBuilder(args);
// Add identity types
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddDefaultTokenProviders();
// Identity Services
builder.Services.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
builder.Services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddTransient<SqlConnection>(e => new SqlConnection(connectionString));
builder.Services.AddTransient<DapperUsersTable>();
// additional configuration
builder.Services.AddRazorPages();
var app = builder.Build();
Ссылки
- Identity Настройка модели
- Пользовательские поставщики служба хранилища для ASP.NET 4.xIdentity
- ASP.NET Core Identity: этот репозиторий содержит ссылки на поставщиков хранилища, поддерживаемых сообществом.
- Просмотреть или скачать образец с GitHub.
ASP.NET Core
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по