Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Секретные ключи предоставляют современный, фишинговый метод проверки подлинности на основе стандартов ВЕБ-аутентификации (WebAuthn) и FIDO2 . Они представляют собой безопасную альтернативу паролям, используя криптографию открытого ключа и проверку подлинности на основе устройств. В этой статье объясняется, как настроить приложение ASP.NET Core для использования ключей доступа для проверки подлинности пользователей.
Рекомендации, относящиеся к новым и существующим Blazor Web App, см. в разделе "Реализация секретных ключей" в ASP.NET Core Blazor Web Appпосле прочтения этой статьи.
Что такое секретные ключи?
Секретные ключи — это замена паролей, использующих пары криптографических ключей. Закрытый ключ хранится безопасно на устройстве пользователя, например в аппаратном модуле безопасности, аутентификаторе платформы (например, Windows Hello, Touch ID, Face ID) или диспетчере паролей, а открытый ключ хранится веб-приложением. Во время проверки подлинности пользователь докажет владение закрытым ключом, не покидая его устройство.
К ключевым преимуществам секретных ключей относятся следующие:
- Фишинговое сопротивление: секретные ключи привязаны к определенным веб-сайтам и не могут использоваться на поддельных сайтах.
- Нет общих секретов: сервер хранит только открытые ключи, устраняя риск нарушений базы данных паролей.
- Удобство пользователя: простая биометрия или проверка ПИН-кода заменяет сложные требования к паролям.
- Синхронизация между устройствами: многие поставщики секретных ключей синхронизируют учетные данные на устройствах пользователя.
Дополнительные сведения см. в разделе API веб-проверки подлинности (документация по MDN).
Ключи доступа в ASP.NET Core Identity
ASP.NET Core Identity включает встроенную поддержку регистрации и проверки подлинности ключей:
- Простая интеграция с Identity инфраструктурой.
- Поддержка проверки подлинности пользователей для наиболее распространенных сценариев WebAuthn.
- Встроенный Blazor Web App в шаблон проекта, поэтому требуется только конфигурация разработчика.
Это важно
Реализация секретного ключа в ASP.NET Core Identity намеренно распространяется на сценарии проверки подлинности. Он не предназначен для библиотеки WebAuthn общего назначения. Разработчики, требующие полной функциональности WebAuthn, должны учитывать библиотеки сообщества, обеспечивающие полную поддержку протокола.
Поддерживаемые сценарии
Реализация ключа доступа ASP.NET Core Identity поддерживает следующие основные сценарии:
- Добавление секретных ключей в существующие учетные записи: пользователи с учетными записями на основе паролей могут регистрировать секретные ключи в качестве дополнительного метода проверки подлинности.
- Создание учетных записей без пароля: пользователи могут создавать учетные записи без пароля, регистрируя пароль при создании учетной записи.
- Вход без пароля: пользователи могут проходить проверку подлинности только с помощью своего секретного ключа без ввода пароля.
Ограничения
Текущая реализация имеет следующие ограничения:
- Область действия ASP.NET Core Identity: API предназначены специально для Identity сценариев проверки подлинности.
- Проверка аттестации по умолчанию не выполняется. Реализация по умолчанию не проверяет операторы аттестации по умолчанию.
- Поддержка шаблонов: только шаблон включает поддержку секретного Blazor Web App ключа.
- Встроенная поддержка 2FA не поддерживается. Секретные ключи рассматриваются как основной фактор проверки подлинности, а не как второй фактор.
Основные понятия
Два фундаментальных процесса лежат в основе операций сквозного ключа: аттестация и утверждение.
Аттестация (регистрация)
Аттестация — это процесс создания и регистрации нового ключа доступа. Во время аттестации сервер создает уникальную проблему, которую аутентификатор должен включать в возвращаемые учетные данные. Средство проверки подлинности создает новую пару ключей и возвращает открытый ключ вместе с данными аттестации, подтверждающими происхождение ключа. Затем сервер проверяет эту аттестацию и сохраняет открытый ключ для будущих попыток проверки подлинности.
Утверждение (проверка подлинности)
Утверждение — это процесс проверки подлинности с помощью существующего секретного ключа. Сервер создает уникальную проблему, которая подписывает средство проверки подлинности с помощью закрытого ключа. Средство проверки подлинности возвращает это подписанное утверждение серверу, которое проверяет подпись с помощью ранее сохраненного открытого ключа. Если подпись действительна, пользователь проходит проверку подлинности.
Предпосылки
- Пакет SDK для .NET (.NET 10 или более поздней версии)
- Современный веб-браузер, поддерживающий WebAuthn.
- Устройство с аутентификатором платформы, например Windows Hello или Apple secure анклава, или ключом безопасности.
Вопросы безопасности
При реализации секретных ключей в ASP.NET Core Identityубедитесь, что приложение соответствует требованиям безопасности, описанным в этом разделе.
Проверка заголовка узла
Реализация определяет идентификатор проверяющей стороны из заголовка узла, если ServerDomain не настроен явным образом. Среда размещения должна проверить заголовки узлов, чтобы предотвратить атаки области учетных данных, которые включают использование скомпрометированных или украденных учетных данных пользователя (имена пользователей, пароли, маркеры), чтобы получить несанкционированный доступ.
Устранение рисков. Явным образом настройте ServerDomainIdentityPasskeyOptions или убедитесь, что среда размещения (KestrelIIS, обратный прокси-сервер) проверяет заголовки узлов. Дополнительные сведения о конфигурации см. в документации по платформе размещения.
Безопасность поддомена
ASP.NET реализация секретных ключей Core обрабатывает безопасность поддомена с помощью ServerDomain параметра конфигурации. Если ServerDomain не указано явно, реализация использует заголовок узла для определения домена. Это означает, что страница, на которой был зарегистрирован секретный ключ, управляет доменом для этих учетных данных.
Рассмотрим пример.
- Если секретный ключ зарегистрирован
app.contoso.comв, он также работает*.app.contoso.com. - Если он зарегистрирован
contoso.com, он также работает*.contoso.com. - Браузер применяет, что ключи доступа можно использовать только в домене (и поддоменах), где они были зарегистрированы.
Требование. Приложения, требующие строгого управления доменом, должны явно задаваться ServerDomain , а не полагаться на заголовок узла. Не обслуживайте ненадежный контент в любой поддомене в ServerDomain области. Если вы не можете гарантировать это, реализуйте настраиваемую проверку происхождения , чтобы ограничить использование секретного ключа определенными источниками.
Требование HTTPS
Для всех операций с ключами доступа требуется ПРОТОКОЛ HTTPS. Реализация хранит данные проверки подлинности в зашифрованных и подписанных файлах cookie, которые могут быть перехвачены через незашифрованные подключения.
Требование. Всегда используйте HTTPS в рабочей среде. Настройте протокол HTTP Strict Transport Security Protocol (HSTS), чтобы предотвратить атаки с понижением уровня протокола.
Восстановление учетной записи
Восстановление учетных записей в первую очередь является проблемой для приложений, которые разрешают секретные ключи в качестве единственного механизма проверки подлинности. Шаблон проекта по умолчанию Blazor Web App уже требует, чтобы пользователи настраивали метод проверки подлинности резервного копирования (пароль или внешний поставщик) при создании учетной записи, поэтому восстановление учетной записи выполняется с помощью этих существующих механизмов.
Рекомендации.
Для приложений, реализующих проверку подлинности только для доступа, рассмотрите:
- Коды восстановления, созданные во время создания учетной записи.
- Потоки восстановления на основе электронной почты.
- Обязательная регистрация нескольких ключей доступа.
- Мониторинг флага IsBackedUp для запроса пользователей UserPasskeyInfo добавить дополнительные учетные данные.
Административные элементы управления
При обнаружении модели проверки подлинности для уязвимостей системы безопасности может потребоваться отозвать затронутые учетные данные. Реализация сохраняет полный объект аттестации с каждым учетным данными, включая GUID аттестации Authenticator (AAGUID), который является 128-разрядным идентификатором, указывающим тип ключа.
Реализация. Извлечение AAGUID из сохраненных объектов аттестации, сравнение с известными скомпрометированных моделей и отзыв затронутых учетных данных. Надежность AAGUID зависит от того, проверяет ли приложение операторы аттестации. Сведения о перехвате в пользовательской логике проверки инструкции аттестации см. в разделе "Проверка настраиваемой аттестации". Сторонние библиотеки доступны для проверки аттестации, таких как секретные ключи — библиотека FIDO2 .NET (репозиторий GitHub)passwordless-lib/fido2-net-lib†.
Предупреждение
библиотеки †Third-party, в том числе passwordless-lib/fido2-net-libне принадлежат или поддерживаются корпорацией Майкрософт и не охватываются каким-либо соглашением о поддержке Майкрософт или лицензией. Используйте осторожность при принятии сторонней библиотеки, особенно для функций безопасности. Убедитесь, что библиотека соответствует официальным спецификациям и принимает рекомендации по обеспечению безопасности. Сохраните текущую версию библиотеки, чтобы получить последние исправления ошибок.
Ограничения ресурсов
Чтобы предотвратить атаки на нехватку базы данных, приложения должны применять ограничения на регистрацию секретного ключа, например:
- Максимальное количество секретных ключей для каждой учетной записи пользователя.
- Максимальная длина отображаемых имен секретного ключа.
Шаблон Blazor Web App применяет эти ограничения по умолчанию на уровне приложения. Примеры см. в следующих Razor компонентах шаблона Blazor Web App проекта:
Замечание
Ссылки в документации на исходный код .NET обычно загружают ветку репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного релиза, используйте раскрывающийся список Переключение ветвей или тегов. Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Настройка параметров секретного ключа
ASP.NET Core Identity предоставляет различные параметры для настройки поведения сквозного ключа через IdentityPasskeyOptions класс, который включает в себя:
- AuthenticatorTimeout: возвращает или задает время, которое браузер должен ожидать, пока средство проверки подлинности предоставит ключ доступа в виде TimeSpan. Этот параметр применяется как к созданию нового ключа доступа, так и к запросу существующего секретного ключа. Этот параметр рассматривается как указание браузеру, и браузер может игнорировать этот параметр. Значение по умолчанию — 5 минут.
- ChallengeSize: получает или задает размер задачи в байтах, отправляемых клиенту во время аттестации и утверждения. Этот параметр применяется как к созданию нового ключа доступа, так и к запросу существующего секретного ключа. Значение по умолчанию — 32 байта.
-
ServerDomain: возвращает или задает действующий идентификатор проверяющей стороны (домен) сервера. Это должно быть уникальным и будет использоваться в качестве удостоверения для сервера. Этот параметр применяется как к созданию нового ключа доступа, так и к запросу существующего секретного ключа. Если
nullиспользуется значение по умолчанию, используется источник сервера. Дополнительные сведения см. в разделе идентификатора RP идентификатора проверяющей стороны.
Пример конфигурации:
builder.Services.Configure<IdentityPasskeyOptions>(options =>
{
options.ServerDomain = "contoso.com";
options.AuthenticatorTimeout = TimeSpan.FromMinutes(3);
options.ChallengeSize = 64;
});
Полный список параметров конфигурации см. в разделе IdentityPasskeyOptions. Для наиболее актуальных настроек браузера по умолчанию см. спецификацию W3C WebAuthn.
Замечание
Ссылки на справочный источник .NET обычно загружают ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего предварительного выпуска .NET. Чтобы выбрать тег для конкретного релиза, используйте раскрывающийся список Переключение ветвей или тегов. Дополнительные сведения см. в разделе "Выбор тега версии" исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Проверка пользовательских инструкций аттестации
По умолчанию ASP.NET Core Identity не проверяет операторы аттестации. Это подходит для большинства сценариев проверки подлинности потребителей. Если приложению требуется проверка свойств аутентификатора или вы хотите запретить использование конкретных аутентификаторов, например в корпоративных средах, для которых требуется более высокий уровень безопасности, можно реализовать настраиваемую проверку аттестации:
builder.Services.Configure<IdentityPasskeyOptions>(options =>
{
options.VerifyAttestationStatement = async (context) =>
{
// Custom attestation validation logic
// Return 'true' if the attestation is valid
// Return 'false' if the attestation is invalid
return true;
};
});
Предупреждение
Проверка аттестации сложна и требует поддержания хранилищ доверия для сертификатов проверки подлинности. Реализуйте только пользовательскую проверку, если приложению требуется проверка определенных свойств аутентификатора.
Проверка пользовательского источника
Проверка происхождения по умолчанию разрешает запросы из поддоменов и запрещает перекрестные iframes. Чтобы настроить это поведение, выполните следующие действия:
builder.Services.Configure<IdentityPasskeyOptions>(options =>
{
options.ValidateOrigin = async (context) =>
{
// Custom origin validation logic
// Access the origin via 'context.Origin'
// Access the HTTP context via 'context.HttpContext'
// Return 'true' if the origin is valid
// Return 'false' if the origin is invalid
return true;
};
});
Поток регистрации
В этом разделе описывается каждый шаг процесса регистрации секретного ключа, объясняющий, как ASP.NET Core Identity упрощает создание и хранение учетных данных секретного ключа.
sequenceDiagram
participant Authenticator
participant User
participant Browser
participant Server
User->>Browser: Click "Add passkey"
Browser->>Server: Request creation options
Server->>Browser: Return creation options
Browser->>Authenticator: Request new credential
Authenticator->>User: Verify identity (biometric/PIN)
User->>Authenticator: Approve
Authenticator->>Browser: Return credential
Browser->>Server: Submit credential
Server->>Server: Verify and store
Server->>Browser: Registration complete
Browser->>User: Success message
Шаг 1. Инициирование регистрации
Процесс регистрации начинается, когда пользователь решает добавить ключ доступа в свою учетную запись. Обычно это происходит через кнопку или ссылку в пользовательском интерфейсе приложения. При выборе этот элемент активирует код JavaScript для оркестрации потока регистрации.
Реализация на стороне клиента значительно зависит от приложений. В шаблоне Blazor Web App можно найти полный пример PasskeySubmit.razor.js, в котором показано, как настраиваемый веб-компонент обрабатывает инициирование регистрации и управляет последующими вызовами API WebAuthn.
Шаг 2. Запрос параметров создания
После регистрации браузер должен получить параметры создания с сервера. Эти параметры сообщают браузеру, какой тип учетных данных необходимо создать и включить важные параметры безопасности, такие как задача, которая должна быть подписана.
С точки зрения браузера этот шаг включает в себя выполнение HTTP-запроса к серверу:
async function createCredential(headers, signal) {
// Step 2: Request creation options from the server
const optionsResponse =
await fetchWithErrorHandling('/Account/PasskeyCreationOptions',
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseCreationOptionsFromJSON(optionsJson);
return await navigator.credentials.create({ publicKey: options, signal });
}
Приложение должно определить конечную точку, которая создает следующие параметры:
app.MapPost("/Account/PasskeyCreationOptions", async (
HttpContext context,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager) =>
{
var user = await userManager.GetUserAsync(context.User);
if (user is null)
{
return Results.NotFound();
}
var userId = await userManager.GetUserIdAsync(user);
var userName = await userManager.GetUserNameAsync(user) ?? "User";
var optionsJson = await signInManager.MakePasskeyCreationOptionsAsync(new()
{
Id = userId,
Name = userName,
DisplayName = userName
});
return TypedResults.Content(optionsJson, contentType: "application/json");
});
Этот MakePasskeyCreationOptionsAsync метод является центральным для этого процесса. Метод принимает описание PasskeyUserEntity пользователя, для которого создается пароль. Эта сущность содержит идентификатор пользователя, имя пользователя (обычно адрес электронной почты) и отображаемое имя пользователя. Метод возвращает строку JSON, соответствующую схеме WebAuthn PublicKeyCredentialCreationOptions , которую браузер использует на следующем шаге. За кулисами этот метод также сохраняет временное состояние в проверке подлинности cookie , чтобы убедиться, что ответ от браузера соответствует этим конкретным параметрам.
Шаг 3. Сервер создает параметры
При MakePasskeyCreationOptionsAsync выполнении используется конфигурация приложения IdentityPasskeyOptions для определения определенных параметров для создания учетных данных. Эти параметры управляют различными аспектами процесса создания секретного ключа.
Эти параметры можно настроить во время запуска приложения. Рассмотрим пример.
builder.Services.Configure<IdentityPasskeyOptions>(options =>
{
options.ServerDomain = "contoso.com";
options.AuthenticatorTimeout = TimeSpan.FromMinutes(3);
options.UserVerificationRequirement = "required";
options.ResidentKeyRequirement = "preferred";
});
Параметр UserVerificationRequirement определяет, должен ли аутентификатор проверить удостоверение пользователя (с помощью биометрических или ПИН-кодов), а ResidentKeyRequirement также указывает, следует ли обнаруживать учетные данные, разрешая проверку подлинности без первого предоставления имени пользователя. Дополнительные сведения см. в разделе IdentityPasskeyOptions.
Шаг 4. Запросы учетных данных клиента
При наличии доступных параметров создания клиентский JavaScript передает параметры API WebAuthn для создания новых учетных данных:
async function createCredential(headers, signal) {
// Step 4: Parse the options and request a new credential from the authenticator
const optionsResponse =
await fetchWithErrorHandling('/Account/PasskeyCreationOptions',
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseCreationOptionsFromJSON(optionsJson);
return await navigator.credentials.create({ publicKey: options, signal });
}
Функция parseCreationOptionsFromJSON преобразует ответ JSON в формат, ожидаемый API WebAuthn, и navigator.credentials.create() инициирует процесс создания учетных данных с помощью средства проверки подлинности.
Шаг 5. Взаимодействие с аутентификатором
На этом этапе браузер взаимодействует с аутентификатором для создания учетных данных. Средство проверки подлинности запрашивает у пользователя проверку, которая может включать сканирование отпечатка пальца, ввод ПИН-кода или распознавание лиц. Это взаимодействие полностью обрабатывается браузером и аутентификатором, не требуя кода приложения. Взаимодействие с пользователем зависит от типа аутентификатора и возможностей платформы.
Шаг 6. Отправка учетных данных
После создания учетных данных средство проверки подлинности браузер должен отправить учетные данные обратно на сервер для проверки и хранения. Перед отправкой учетные данные должны быть сериализованы в JSON:
async function createCredential(headers, signal) {
// Step 6: The credential is returned from navigator.credentials.create()
// and is serialized to JSON for submission to the server
const optionsResponse =
await fetchWithErrorHandling('/Account/PasskeyCreationOptions',
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseCreationOptionsFromJSON(optionsJson);
return await navigator.credentials.create({ publicKey: options, signal });
}
В шаблоне Blazor Web App возвращенные учетные данные автоматически сериализуются и передаются через форму, но точный механизм отправки зависит от приложения.
Шаг 7. Проверка сервера и хранилище
Когда сервер получает учетные данные, он должен проверить его допустимость и сохранить открытый ключ для будущей проверки подлинности. Это место, где ASP.NET API ключей core Identityстановятся критически важными.
Метод PerformPasskeyAttestationAsync проверяет ответ аттестации от клиента. Этот комплексный процесс проверки:
- Проверяет, соответствует ли тип учетных данных ожиданиям.
- Проверяет данные клиента, включая источник и вызов.
- Проверяет флаги данных аутентификатора для присутствия и проверки пользователей
- Извлекает и проверяет открытый ключ.
Если все проверки проходят, метод возвращает PasskeyAttestationResult сведения о проверенном ключе.
После проверки аттестации приложение использует AddOrUpdatePasskeyAsync для хранения секретного ключа в базе данных:
var attestationResult =
await signInManager.PerformPasskeyAttestationAsync(credentialJson);
if (!attestationResult.Succeeded)
{
return Results.BadRequest($"Error: {attestationResult.Failure.Message}");
}
var addResult =
await userManager.AddOrUpdatePasskeyAsync(user, attestationResult.Passkey);
if (!addResult.Succeeded)
{
return Results.BadRequest("Failed to store passkey");
}
Хранящийся UserPasskeyInfo содержит все необходимые сведения для будущей проверки подлинности, включая идентификатор учетных данных, открытый ключ, счетчик подписей для защиты воспроизведения и флаги, указывающие, выполняется ли резервное копирование или возможность резервного копирования.
Шаг 8. Задачи после регистрации
После успешной регистрации секретного ключа приложения часто выполняют дополнительные задачи, чтобы улучшить взаимодействие с пользователем. Распространенным шаблоном является запрос пользователей на предоставление понятного имени для их секретного ключа, что упрощает идентификацию среди нескольких учетных данных. Свойство UserPasskeyInfo.Name сохраняет это понятное для пользователя имя, которое можно обновить с помощью того же AddOrUpdatePasskeyAsync метода:
passkey.Name = "My iPhone";
await userManager.AddOrUpdatePasskeyAsync(user, passkey);
Поток аутентификации
В этом разделе объясняется, как пользователи проходят проверку подлинности с помощью ключей доступа, начиная от запуска процесса входа в систему до создания сеанса, прошедшего проверку подлинности.
sequenceDiagram
participant Authenticator
participant User
participant Browser
participant Server
User->>Browser: Click "Sign in with passkey"
Browser->>Server: Request authentication options
Server->>Browser: Return authentication options
Browser->>Authenticator: Request assertion
Authenticator->>User: Verify identity
User->>Authenticator: Approve
Authenticator->>Browser: Return signed assertion
Browser->>Server: Submit assertion
Server->>Server: Verify signature
Server->>Browser: Authentication complete
Browser->>User: Redirect to app
Шаг 1. Инициирование проверки подлинности
Обычно пользователи инициируют сквозную проверку подлинности с помощью выделенной кнопки или ссылки на странице входа. Некоторые приложения также поддерживают условный пользовательский интерфейс, где ключи доступа отображаются как предложения автозаполнения в поле имени пользователя. Метод запуска активирует код JavaScript, который управляет потоком проверки подлинности, аналогичным процессу регистрации.
Шаг 2. Запрос параметров проверки подлинности
Браузер запрашивает параметры проверки подлинности с сервера, чтобы начать процесс проверки подлинности. К этим параметрам относятся список допустимых учетных данных и новая задача для подписи:
async function requestCredential(email, mediation, headers, signal) {
// Step 2: Request authentication options from the server
const optionsResponse =
await fetchWithErrorHandling(`/Account/PasskeyRequestOptions?username=${email}`,
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseRequestOptionsFromJSON(optionsJson);
return await navigator.credentials.get({ publicKey: options, mediation, signal });
}
Метод MakePasskeyRequestOptionsAsync создает эти параметры. При предоставлении определенного пользователя он содержит только учетные данные этого пользователя в списке разрешений. При вызове без пользователя он создает параметры, подходящие для условного пользовательского интерфейса или проверки подлинности без имени пользователя:
app.MapPost("/Account/PasskeyRequestOptions", async (
SignInManager<ApplicationUser> signInManager,
string? username) =>
{
var user = string.IsNullOrEmpty(username)
? null
: await userManager.FindByNameAsync(username);
var optionsJson = await signInManager.MakePasskeyRequestOptionsAsync(user);
return TypedResults.Content(optionsJson, contentType: "application/json");
});
Шаг 3. Сервер создает параметры
Сервер создает параметры проверки подлинности с помощью той же IdentityPasskeyOptions конфигурации, используемой во время регистрации. Должен ServerDomain соответствовать домену, в котором пароль был зарегистрирован первоначально или проверка подлинности завершается ошибкой. Определяет UserVerificationRequirement , должен ли аутентификатор проверить удостоверение пользователя во время проверки подлинности.
Шаг 4. Утверждение запросов клиентов
JavaScript на стороне клиента передает параметры проверки подлинности API WebAuthn, чтобы запросить утверждение от аутентификатора:
async function requestCredential(email, mediation, headers, signal) {
// Step 4: Parse the options and request an assertion from the authenticator
const optionsResponse =
await fetchWithErrorHandling(`/Account/PasskeyRequestOptions?username=${email}`,
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseRequestOptionsFromJSON(optionsJson);
return await navigator.credentials.get({ publicKey: options, mediation, signal });
}
Вызов navigator.credentials.get() инициирует процесс проверки подлинности с помощью средства проверки подлинности, который запрашивает у пользователя проверку подлинности.
Шаг 5. Проверка подлинности
Средство проверки подлинности проверяет удостоверение пользователя и подписывает вызов с помощью закрытого ключа. Этот процесс полностью обрабатывается браузером и аутентификатором, аналогичным шагу проверки во время регистрации. Взаимодействие с пользователем зависит от типа аутентификатора и может включать биометрическую проверку или запись ПИН-кода.
Шаг 6. Отправка утверждения
После создания подписанного утверждения браузер сериализует его в JSON и отправляет его на сервер:
async function requestCredential(email, mediation, headers, signal) {
// Step 6: The assertion is returned from navigator.credentials.get()
// and is serialized to JSON for submission to the server
const optionsResponse =
await fetchWithErrorHandling(`/Account/PasskeyRequestOptions?username=${email}`,
{
method: 'POST',
headers,
signal,
});
const optionsJson = await optionsResponse.json();
const options = PublicKeyCredential.parseRequestOptionsFromJSON(optionsJson);
return await navigator.credentials.get({ publicKey: options, mediation, signal });
}
Механизм отправки зависит от приложения, но обычно включает отправку формы или вызов API.
Шаг 7. Проверка сервера
Сервер проверяет утверждение для проверки подлинности пользователя. ASP.NET Core Identity предоставляет PasskeySignInAsync метод, который выполняет полный поток проверки подлинности в одном вызове:
var result = await signInManager.PasskeySignInAsync(credentialJson);
if (result.Succeeded)
{
return Results.Ok("Authentication successful");
}
return Results.Unauthorized();
Метод PasskeySignInAsync внутренних вызовов:PerformPasskeyAssertionAsync
- Проверьте подпись утверждения с помощью сохраненного открытого ключа.
- Убедитесь, что задача соответствует первоначально отправленной.
- Проверьте флаги аутентификатора для присутствия и проверки пользователей.
- Обновите счетчик подписи, чтобы предотвратить атаки воспроизведения.
Если все проверки проходят, метод выполняет вход пользователя и возвращает результат успешного SignInResult выполнения.
Для сценариев, требующих большего контроля, можно использовать PerformPasskeyAssertionAsync непосредственно для проверки утверждения без немедленного входа пользователя:
- PerformPasskeyAssertionAsync PasskeyAssertionResult возвращает данные, содержащие прошедших проверку подлинности пользователя и обновленные сведения о ключе доступа.
- Так как флаги входа и аутентификатора секретного ключа могут измениться с момента последнего утверждения, а обновленный секретный ключ не сохраняется автоматически при вызове PerformPasskeyAssertionAsync, вызов UserManager<TUser>.AddOrUpdatePasskeyAsync с возвращенным PasskeyAssertionResult.
Шаг 8. Создание сеанса
После успешной проверки подлинности ASP.NET Core Identity устанавливает прошедший проверку подлинности сеанс для пользователя. Этот PasskeySignInAsync метод обрабатывается автоматически, создавая необходимые файлы cookie проверки подлинности и утверждения. Затем приложение перенаправляет пользователя на защищенные ресурсы или отображает персонализированное содержимое.
Смягчить PublicKeyCredential.toJSON ошибку (TypeError: Illegal invocation)
МетодPublicKeyCredential.toJSON возвращает представление JSON объектаPublicKeyCredential. Метод вызывается диспетчером паролей, когда приложение пытается сериализовать PublicKeyCredential посредством вызова JSON.stringify при регистрации или проверке подлинности пользователя.
Некоторые диспетчеры паролей не правильно реализуют метод PublicKeyCredential.toJSON, который необходим для работы JSON.stringify при сериализации учетных данных пароля. При регистрации или аутентификации пользователя в приложении, созданном на основе шаблона проекта Blazor Web App, при попытке добавить ключ доступа возникает следующая ошибка.
Error: Could not add a passkey: Illegal invocation
Пока выбранный диспетчер паролей не будет обновлен для правильной PublicKeyCredential.toJSON реализации метода, внесите следующие изменения в приложение. Следующий код вручную сериализует JSON PublicKeyCredential.
В файле Components/Account/Shared/PasskeySubmit.razor.js найдите блок кода определения passkey-submit пользовательского элемента.
customElements.define('passkey-submit', class extends HTMLElement {
...
});
Добавьте следующую convertToBase64 функцию в блок кода:
convertToBase64(o) {
if (!o) {
return undefined;
}
// Normalize Array to Uint8Array
if (Array.isArray(o)) {
o = Uint8Array.from(o);
}
// Normalize ArrayBuffer to Uint8Array
if (o instanceof ArrayBuffer) {
o = new Uint8Array(o);
}
// Convert Uint8Array to base64
if (o instanceof Uint8Array) {
let str = '';
for (let i = 0; i < o.byteLength; i++) {
str += String.fromCharCode(o[i]);
}
o = window.btoa(str);
}
if (typeof o !== 'string') {
throw new Error("Could not convert to base64 string");
}
// Convert base64 to base64url
o = o.replace(/\+/g, "-").replace(/\//g, "_").replace(/=*$/g, "");
return o;
}
В функции obtainAndSubmitCredential в блоке кода найдите строку, которая вызывает JSON.stringify с учетными данными пользователя, и удалите эту строку.
- const credentialJson = JSON.stringify(credential);
Замените предыдущую строку следующим кодом:
const credentialJson = JSON.stringify({
authenticatorAttachment: credential.authenticatorAttachment,
clientExtensionResults: credential.getClientExtensionResults(),
id: credential.id,
rawId: this.convertToBase64(credential.rawId),
response: {
attestationObject: this.convertToBase64(credential.response.attestationObject),
authenticatorData: this.convertToBase64(credential.response.authenticatorData ??
credential.response.getAuthenticatorData?.() ?? undefined),
clientDataJSON: this.convertToBase64(credential.response.clientDataJSON),
publicKey: this.convertToBase64(credential.response.getPublicKey?.() ?? undefined),
publicKeyAlgorithm: credential.response.getPublicKeyAlgorithm?.() ?? undefined,
transports: credential.response.getTransports?.() ?? undefined,
signature: this.convertToBase64(credential.response.signature),
userHandle: this.convertToBase64(credential.response.userHandle),
},
type: credential.type,
});
Указанное выше обходное решение требуется только до тех пор, пока диспетчер паролей не будет обновлен для реализации метода PublicKeyCredential.toJSON корректным образом. Мы рекомендуем отслеживать заметки о выпуске диспетчера паролей и отменять предыдущие изменения после обновления диспетчера паролей.
Дополнительные ресурсы
ASP.NET Core