Защита ASP.NET Core Blazor WebAssembly с помощью ASP.NET Core Identity

Blazor WebAssembly Автономные приложения можно защитить с помощью ASP.NET CoreIdentity, следуя инструкциям в этой статье.

Конечные точки для регистрации, входа в систему и выхода из системы

Вместо использования пользовательского интерфейса по умолчанию, предоставленного ASP.NET Core Identity для SPA и Blazor приложений, который основан на Razor страницах, вызовите MapIdentityApi внутренний API для добавления JSконечных точек ON API для регистрации и входа пользователей с ASP.NET Core Identity. Identity Конечные точки API также поддерживают расширенные функции, такие как двухфакторная проверка подлинности и проверка электронной почты.

На клиенте вызовите /register конечную точку, чтобы зарегистрировать пользователя с помощью адреса электронной почты и пароля:

var result = await _httpClient.PostAsJsonAsync(
    "register", new
    {
        email,
        password
    });

В клиенте войдите в систему пользователя с проверкой подлинности с cookie помощью конечной точки со useCookies строкой запроса, заданной /login в trueследующих значениях:

var result = await _httpClient.PostAsJsonAsync(
    "login?useCookies=true", new
    {
        email,
        password
    });

API серверного сервера устанавливает cookie проверку подлинности с вызовом AddIdentityCookies в построителе проверки подлинности:

builder.Services
    .AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddIdentityCookies();

Проверка подлинности на базе токенов

Для собственных и мобильных сценариев, когда некоторые клиенты не поддерживают cookieфункции входа, API входа предоставляет параметр для запроса маркеров. Выдается пользовательский маркер (который является владельцем платформы ASP.NET Core Identity ), который можно использовать для проверки подлинности последующих запросов. Маркер должен передаваться в заголовке Authorization в качестве маркера носителя. Также предоставляется маркер обновления. Этот маркер позволяет приложению запрашивать новый маркер, когда срок действия старого маркера истекает без повторного входа пользователя.

Маркеры не являются стандартными JSвеб-токенами ON (JWTs). Использование пользовательских маркеров намеренно, так как встроенный Identity API предназначен в первую очередь для простых сценариев. Параметр токена не предназначен для полнофункционального поставщика службы удостоверений или сервера маркеров, а вместо этого альтернативой cookie варианту для клиентов, которые не могут использовать cookieего.

В следующем руководстве начинается процесс реализации проверки подлинности на основе маркеров с помощью API входа. Для завершения реализации требуется пользовательский код. Дополнительные сведения см. в статье "Защита Identity серверной части веб-API для spAs".

Вместо API серверного сервера, устанавливающего cookie проверку подлинности с вызовом AddIdentityCookies в построителе проверки подлинности, API сервера настраивает проверку подлинности маркера носителя с AddBearerToken помощью метода расширения. Укажите схему маркеров проверки подлинности носителя с IdentityConstants.BearerSchemeпомощью .

В Backend/Program.csэтом случае измените службы проверки подлинности и конфигурацию следующим образом:

builder.Services
    .AddAuthentication()
    .AddBearerToken(IdentityConstants.BearerScheme);

Удалите BlazorWasmAuth/Identity/CookieAuthenticationStateProvider.csпараметр строки запроса в методе LoginAsyncCookieAuthenticationStateProvider:useCookies

- login?useCookies=true
+ login

На этом этапе необходимо предоставить пользовательский код для анализа AccessTokenResponse клиента и управления маркерами доступа и обновления. Дополнительные сведения см. в статье "Защита Identity серверной части веб-API для spAs".

Дополнительные Identity сценарии

Дополнительные Identity сценарии, предоставляемые API, см. в статье "Использование Identity для защиты серверной части веб-API для spAs:

  • Защита выбранных конечных точек
  • Проверка подлинности на базе токенов
  • Двухфакторная проверка подлинности (2FA)
  • Коды восстановления
  • Управление сведениями пользователей

Примеры приложений

В этой статье примеры приложений служат ссылкой для автономных Blazor WebAssembly приложений, которые обращаются к ASP.NET Core Identity через внутренний веб-API. Демонстрация включает в себя два приложения:

  • Backend: серверное веб-ПРИЛОЖЕНИЕ API, которое поддерживает хранилище удостоверений пользователя для ASP.NET Core Identity.
  • BlazorWasmAuth: автономное Blazor WebAssembly интерфейсное приложение с проверкой подлинности пользователя.

Перейдите к примеру приложений через последнюю папку версии из корневого каталога репозитория, используя следующую ссылку. Примеры предоставляются для .NET 8 или более поздней версии. Сведения о запуске примеров приложений см. README в BlazorWebAssemblyStandaloneWithIdentity папке в папке.

Просмотреть или скачать образец кода (описание загрузки)

Пакеты и код внутреннего веб-API веб-API

Серверное веб-ПРИЛОЖЕНИЕ API поддерживает хранилище удостоверений пользователя для ASP.NET Core Identity.

Пакеты

Приложение использует следующие пакеты NuGet:

Если приложение предназначено для использования другого EF Core поставщика базы данных, отличного от поставщика в памяти, не создавайте ссылку на пакет в приложении Microsoft.EntityFrameworkCore.InMemory.

В файле проекта приложения (.csproj) настраивается инвариантная глобализация .

Пример кода приложения

Параметры приложения настраивают внутренние и внешние URL-адреса:

  • Backend приложение (BackendUrl): https://localhost:7211
  • BlazorWasmAuth приложение (FrontendUrl): https://localhost:7171

Файл Backend.http можно использовать для тестирования запроса данных о погоде. Обратите внимание, что BlazorWasmAuth приложение должно выполняться для тестирования конечной точки, а конечная точка жестко закодирована в файл. Дополнительные сведения см. в статье "Использование HTTP-файлов в Visual Studio 2022".

Следующая настройка и конфигурация находятся в файле приложенияProgram.

Удостоверение пользователя с cookie проверкой подлинности добавляется путем вызова AddAuthentication и AddIdentityCookies. Службы для авторизации проверка добавляются вызовомAddAuthorizationBuilder.

Рекомендуется только для демонстраций, приложение использует EF Core поставщика базы данных в памяти для регистрации контекста базы данных (AddDbContext). Поставщик базы данных в памяти упрощает перезапуск приложения и проверяет потоки пользователей регистрации и входа. Каждое выполнение начинается с новой базы данных, но приложение включает тестовый демонстрационный код для пользователей, который описан далее в этой статье. Если база данных изменена на SQLite, пользователи сохраняются между сеансами, но база данных должна быть создана с помощью миграций, как показано в руководстве по началу EF Core работы. Для рабочего кода можно использовать другие реляционные поставщики, такие как SQL Server.

Настройте Identity для использования EF Core базы данных и предоставления Identity конечных точек через вызовы AddIdentityCore, AddEntityFrameworkStoresа также AddApiEndpoints.

Политика общего доступа к ресурсам (CORS) между источниками устанавливается для разрешения запросов от интерфейсных и внутренних приложений. Резервные URL-адреса настраиваются для политики CORS, если параметры приложения не предоставляют их:

  • Backend приложение (BackendUrl): https://localhost:5001
  • BlazorWasmAuth приложение (FrontendUrl): https://localhost:5002

Службы и конечные точки для Swagger/OpenAPI включены в документацию по веб-API и тестирование разработки. Дополнительные сведения о NSwag см. в статье "Начало работы с NSwag" и ASP.NET Core.

Утверждения роли пользователя отправляются из минимального API на конечной точке/roles.

Маршруты сопоставляются для Identity конечных точек путем вызова MapIdentityApi<AppUser>().

Конечная точка выхода (/Logout) настраивается в конвейере ПО промежуточного слоя для выхода пользователей.

Чтобы защитить конечную точку, добавьте RequireAuthorization метод расширения в определение маршрута. Для контроллера добавьте атрибут в [Authorize] контроллер или действие.

Дополнительные сведения о базовых шаблонах инициализации и конфигурации экземпляра DbContext см. в EF Core документации по времени существования, конфигурации и инициализации DbContext.

Пакеты и код автономных Blazor WebAssembly приложений frontend

Автономное Blazor WebAssembly интерфейсное приложение демонстрирует проверку подлинности пользователей и авторизацию для доступа к частной веб-странице.

Пакеты

Приложение использует следующие пакеты NuGet:

Пример кода приложения

Папка Models содержит модели приложения:

Интерфейс IAccountManagement (Identity/CookieHandler.cs) предоставляет службы управления учетными записями.

Класс () обрабатывает состояние проверки подлинности на cookieоснове и предоставляет реализации службы управления учетными записями, описанные в интерфейсеIAccountManagement.Identity/CookieAuthenticationStateProvider.csCookieAuthenticationStateProvider Метод LoginAsync явно включает cookie проверку подлинности через useCookies строковое значение trueзапроса. Класс также управляет созданием утверждений ролей для прошедших проверку подлинности пользователей.

Класс CookieHandler (Identity/CookieHandler.cs) гарантирует, что cookie учетные данные отправляются с каждым запросом на внутренний веб-API, который обрабатывает Identity и поддерживает Identity хранилище данных.

Предоставляет wwwroot/appsettings.file конечные точки внутренних и интерфейсных URL-адресов.

Компонент App предоставляет состояние проверки подлинности в виде каскадного параметра. Дополнительные сведения см. в разделе ASP.NET Проверка подлинности и авторизация CoreBlazor.

Компонент MainLayout и NavMenu компонент используют AuthorizeView компонент для выборочного отображения содержимого на основе состояния проверки подлинности пользователя.

Следующие компоненты обрабатывают распространенные задачи проверки подлинности пользователей IAccountManagement , используя службы:

Компонент PrivatePage (Components/Pages/PrivatePage.razor) требует проверки подлинности и отображает утверждения пользователя.

Службы и конфигурация предоставляются в Program файле (Program.cs):

  • Обработчик cookie зарегистрирован в качестве область службы.
  • Службы авторизации регистрируются.
  • Настраиваемый поставщик состояния проверки подлинности зарегистрирован в качестве службы область.
  • Регистрируется интерфейсIAccountManagement управления учетными записями.
  • URL-адрес базового узла настроен для зарегистрированного экземпляра клиента HTTP.
  • Базовый внутренний URL-адрес настраивается для зарегистрированного экземпляра клиента HTTP, который используется для проверки подлинности с серверным веб-API. HTTP-клиент использует cookie обработчик, чтобы убедиться, что cookie учетные данные отправляются с каждым запросом.

Вызов при AuthenticationStateProvider.NotifyAuthenticationStateChanged изменении состояния проверки подлинности пользователя. Пример см LoginAsync . в разделе и LogoutAsync методы CookieAuthenticationStateProvider класса (Identity/CookieAuthenticationStateProvider.cs).

Предупреждение

Компонент AuthorizeView избирательно демонстрирует содержимое пользовательского интерфейса в зависимости от того, авторизован ли пользователь. Все содержимое в приложении, размещенном в компоненте Blazor WebAssemblyAuthorizeView , доступно без проверки подлинности, поэтому конфиденциальное содержимое должно быть получено из веб-API на серверном сервере после успешной проверки подлинности. Дополнительные сведения см. на следующих ресурсах:

Тестовая демонстрация заполнения пользователей

Класс SeedData (SeedData.cs) демонстрирует создание тестовых пользователей для разработки. Тестовый пользователь с именем Leela войдите в приложение с помощью адреса leela@contoso.comэлектронной почты. Для пароля пользователя задано Passw0rd!значение . Leela предоставляется Administrator и Manager роли для авторизации, что позволяет пользователю получить доступ к странице руководителя, /private-manager-page но не на странице /private-editor-pageредактора.

Предупреждение

Никогда не разрешать запуск тестового пользовательского кода в рабочей среде. SeedData.InitializeAsync вызывается только в Development среде в Program файле:

if (builder.Environment.IsDevelopment())
{
    await using var scope = app.Services.CreateAsyncScope();
    await SeedData.InitializeAsync(scope.ServiceProvider);
}

Роли

Из-за проблемы с проектированием платформы (dotnet/aspnetcore #50037) утверждения ролей не отправляются из manage/info конечной точки для создания утверждений пользователей для пользователей BlazorWasmAuth приложения. Утверждения ролей управляются независимо через отдельный запрос в GetAuthenticationStateAsync методеCookieAuthenticationStateProviderкласса (Identity/CookieAuthenticationStateProvider.cs) после проверки подлинности пользователя в Backend проекте.

В запросе CookieAuthenticationStateProviderролей выполняется /roles запрос на конечную точку Backend проекта API сервера. Ответ считывается в строку путем вызова ReadAsStringAsync(). JsonSerializer.Deserialize десериализирует строку в пользовательский RoleClaim массив. Наконец, утверждения добавляются в коллекцию утверждений пользователя.

В файле API Program сервера минимальный Backend API управляет конечной /roles точкой. RoleClaimType Утверждения выбираются в анонимный тип и сериализуются для возврата в BlazorWasmAuth проект.TypedResults.Json

Конечная точка ролей требует авторизации путем вызова RequireAuthorization. Если вы решили не использовать минимальные API в пользу контроллеров для конечных точек API безопасного сервера, обязательно установите [Authorize] атрибут на контроллерах или действиях.

Размещение между доменами (конфигурация одного сайта)

Примеры приложений настроены для размещения обоих приложений в одном домене. Если приложение размещается Backend в другом домене, отличном BlazorWasmAuth от приложения, раскомментируйте код, который настраивает cookie (ConfigureApplicationCookie) в Backend файле приложения Program . Значения по умолчанию:

Измените значения следующими значениями:

- options.Cookie.SameSite = SameSiteMode.Lax;
- options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
+ options.Cookie.SameSite = SameSiteMode.None;
+ options.Cookie.SecurePolicy = CookieSecurePolicy.Always;

Дополнительные сведения о параметрах одного сайта cookie см. в следующих ресурсах:

Поддержка антифоргерии

Только конечная точка выхода (/logout) в Backend приложении требует внимания для устранения угрозы кросс-сайта Forgery (CSRF).

Конечная точка выхода проверка пустого текста, чтобы предотвратить атаки CSRF. Если требуется текст, запрос должен выполняться из JavaScript, который является единственным способом доступа к проверке подлинности cookie. Конечная точка выхода не может быть доступ к ней с помощью POST на основе форм. Это предотвращает выход злоумышленника из системы.

Кроме того, конечная точка защищена авторизацией (RequireAuthorization), чтобы предотвратить анонимный доступ.

Клиентское BlazorWasmAuth приложение просто необходимо передать пустой объект {} в тексте запроса.

За пределами конечной точки выхода защита от угроз требуется только при отправке данных формы на сервер, закодированный как application/x-www-form-urlencoded, multipart/form-dataили text/plain. Blazor Управляет устранением рисков CSRF для форм в большинстве случаев. Дополнительные сведения см. в статье ASP.NET Проверка подлинности и авторизация Core Blazor и обзор ASP.NET основных Blazor форм.

Запросы к другим конечным точкам API сервера (веб-API) с содержимым с application/jsonкодировкой CORS не требуют защиты CSRF. Поэтому для конечной точки обработки данных (/data-processing) приложения не требуется Backend защита CSRF. Конечная точка ролей/roles не нуждается в защите CSRF, так как это конечная точка GET, которая не изменяет состояние.

Устранение неполадок

Ведение журнала

Сведения о включении ведения журнала отладки или трассировки для Blazor WebAssembly проверки подлинности см. в разделе ASP.NET ведения журнала CoreBlazor.

Распространенные ошибки

Проверьте конфигурацию каждого проекта. Убедитесь, что URL-адреса верны:

  • Backend Проекта
    • appsettings.json
      • BackendUrl
      • FrontendUrl
    • Backend.http: Backend_HostAddress
  • BlazorWasmAuth Проекта: wwwroot/appsettings.json
    • BackendUrl
    • FrontendUrl

Если конфигурация верна, выполните приведенные ниже действия.

  • Проанализируйте журналы приложений.

  • Изучите сетевой трафик между приложением BlazorWasmAuth и Backend приложением с помощью средств разработчика браузера. Часто точное сообщение об ошибке или сообщение с подсказкой о том, что вызывает проблему, возвращается клиенту серверным приложением после выполнения запроса. Руководство по инструментам разработчика можно найти в следующих статьях:

  • Google Chrome (документация по Google)

  • Microsoft Edge

  • Mozilla Firefox (документация по Mozilla)

Команда документации отвечает на отзывы о документах и ошибки в статьях. Откройте проблему, используя ссылку "Открыть документацию" в нижней части статьи. Команда не может предоставлять поддержку продукта. Помощь в устранении неполадок в приложении предоставляют несколько общественных форумов поддержки. Мы рекомендуем следующее:

Указанные выше форумы не принадлежат корпорации Майкрософт и не управляются ею.

Чтобы сообщить об ошибках с воспроизведением платформы, которые не связаны с безопасностью и конфиденциальностью, откройте запрос с единицей продукта ASP.NET Core. Не открывайте запрос с единицей продукта, пока вы тщательно не изучите причину проблемы и не попытаетесь решить ее самостоятельно или с помощью сообщества на общедоступном форуме поддержки. Единица продукта не способна устранять неполадки отдельных приложений, которые не работают из-за неправильной конфигурации или вариантов использования с участием сторонних служб. Если отчет является конфиденциальным или конфиденциальным в природе или описывает потенциальный недостаток безопасности в продукте, который злоумышленники могут использовать, см. статью "Отчеты о проблемах безопасности и ошибках" (dotnet/aspnetcoreрепозиторий GitHub).

Файлы Cookie и данные сайта

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

  • файлы cookie входа пользователя;
  • файлы cookie приложения;
  • кэшированные и сохраненные данные сайта.

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

  • Настройка браузера
    • Для тестирования используйте браузер, в котором можно настроить удаление всех файлов cookie и данных сайта при каждом закрытии браузера.
    • Убедитесь, что при любых изменениях в приложении, в данных тестового пользователя или в конфигурации поставщика закрытие браузера выполняется вручную или интегрированной средой разработки.
  • Используйте пользовательскую команду, чтобы открыть браузер в режиме InPrivate или Incognito в Visual Studio:
    • Откройте диалоговое окно Просмотр с помощью, которое можно выбрать с помощью кнопки Запустить в Visual Studio.
    • Нажмите кнопку Добавить.
    • Укажите путь к браузеру в поле Программа. Следующие пути к исполняемым файлам являются типичными расположениями установки для Windows 10. Если браузер установлен в другом расположении или вы используете операционную систему, отличную от Windows 10, укажите путь к исполняемому файлу браузера.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • В поле "Аргументы" укажите параметр командной строки, который браузер использует для открытия в режиме InPrivate или Incognito. Для некоторых браузеров требуется URL-адрес приложения.
      • Microsoft Edge: используйте -inprivate.
      • Google Chrome: используйте --incognito --new-window {URL}, где заполнитель {URL} является URL-адресом для открытия (например, https://localhost:5001).
      • Mozilla Firefox: используйте -private -url {URL}, где заполнитель {URL} является URL-адресом для открытия (например, https://localhost:5001).
    • Введите имя в поле Понятное имя. Например, Firefox Auth Testing.
    • Выберите кнопку ОК.
    • Чтобы не выбирать профиль браузера для каждой операции тестирования с помощью приложения, задайте профиль по умолчанию с помощью кнопки По умолчанию.
    • Убедитесь, что при любых изменениях в приложении, в данных тестового пользователя или в конфигурации поставщика закрытие браузера выполняется интегрированной средой разработки.

Обновление приложений

Приложения-функции могут перестать работать сразу после обновления пакета SDK для .NET Core на компьютере разработки или обновления версии пакетов в самом приложении. В некоторых случаях в результате важного обновления несогласованные версии пакетов могут привести к нарушению работы приложения. Большинство этих проблем можно исправить следующим образом:

  1. Очистите кэши пакетов NuGet локальных систем, выполнив команду dotnet nuget locals all --clear из командной оболочки.
  2. Удалите папки bin и obj проекта.
  3. Восстановите и перестройте проект.
  4. Удалите все файлы из папки развертывания на сервере, прежде чем повторно развернуть приложение.

Примечание.

Использование версий пакета, несовместимых с требуемой платформой приложения, не поддерживается. Дополнительные сведения о пакете см. на странице коллекций NuGet или обозревателя пакетов FuGet.

Проверка утверждений пользователя

Чтобы устранить неполадки с утверждениями пользователей, следующий UserClaims компонент можно использовать непосредственно в приложениях или служить основой для дальнейшей настройки.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

**Name**: @AuthenticatedUser?.Identity?.Name

<h2>Claims</h2>

@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
    <p class="claim">@(claim.Type): @claim.Value</p>
}

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? AuthenticationState { get; set; }

    public ClaimsPrincipal? AuthenticatedUser { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthenticationState is not null)
        {
            var state = await AuthenticationState;
            AuthenticatedUser = state.User;
        }
    }
}

Дополнительные ресурсы