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


Защита ASP.NET Core Blazor Web App с помощью OpenID Connect (OIDC)

В этой статье описывается, как защитить Blazor Web App приложение OpenID Connect (OIDC) с помощью примера приложения в dotnet/blazor-samples репозитории GitHub (.NET 8 или более поздней версии) (как скачать).

Эта версия статьи охватывает реализацию OIDC без внедрения шаблона Серверной части для внешнего интерфейса (BFF). Шаблон BFF полезен для выполнения аутентифицированных запросов к внешним службам. Измените селектор версии статьи на OIDC с шаблоном BFF, если спецификация приложения вызывает внедрение шаблона BFF.

Рассматривается следующая спецификация:

  • Использует Blazor Web App режим автоматической отрисовки с глобальной интерактивностью.
  • Пользовательские службы поставщика состояний проверки подлинности используются сервером и клиентскими приложениями для записи состояния проверки подлинности пользователя и потока между сервером и клиентом.
  • Это приложение является отправной точкой для любого потока проверки подлинности OIDC. OIDC настраивается вручную в приложении и не зависит от идентификатора Microsoft Entra или веб-пакетов МайкрософтIdentity, а также не требует размещения Microsoft Azure. Однако пример приложения можно использовать с Entra, Microsoft Identity Web и размещаться в Azure.
  • Автоматическое обновление неинтерактивного маркера.
  • Безопасно вызывает (веб-) API в серверном проекте для данных.

Пример приложения

Пример приложения состоит из двух проектов:

  • BlazorWebAppOidc: серверный проект объекта Blazor Web App, содержащий пример минимальной конечной точки API для данных погоды.
  • BlazorWebAppOidc.Client: клиентский проект объекта Blazor Web App.

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

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

Серверный Blazor Web App проект (BlazorWebAppOidc)

Проект BlazorWebAppOidc является серверным проектом Blazor Web App.

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

Примечание.

Серверный проект используется, но никогда не используется IHttpContextAccessor/HttpContextдля интерактивных отрисованных компонентов. Дополнительные сведения см. в руководстве по устранению угроз для интерактивной отрисовки на стороне сервера ASP.NET CoreBlazor.

Настройка

В этом разделе объясняется, как настроить пример приложения.

Примечание.

Для идентификатора Microsoft Entra или Azure AD B2C можно использовать AddMicrosoftIdentityWebApp из Microsoft Identity Web (Microsoft.Identity.Web пакет NuGet, документация по API), которая добавляет обработчики OIDC и Cookie проверки подлинности с соответствующими значениями по умолчанию. Пример приложения и руководство в этом разделе не используют Microsoft Identity Web. В руководстве показано, как настроить обработчик OIDC вручную для любого поставщика OIDC. Дополнительные сведения о реализации Microsoft Identity Web см. в связанных ресурсах.

Установка секрета клиента

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

Не сохраняйте секреты приложений, строка подключения, учетные данные, пароли, персональные идентификационные номера (ПИН-коды), частный код C#/.NET или закрытые ключи и токены в клиентском коде, который всегда небезопасн. В средах тестирования и промежуточной и рабочей среды код на стороне Blazor сервера и веб-API должны использовать безопасные потоки проверки подлинности, которые не поддерживают учетные данные в файлах кода проекта или конфигурации. Вне локального тестирования разработки рекомендуется избегать использования переменных среды для хранения конфиденциальных данных, так как переменные среды не являются наиболее безопасным подходом. Для локального тестирования разработки средство Secret Manager рекомендуется для защиты конфиденциальных данных. Дополнительные сведения см. в разделе "Безопасное обслуживание конфиденциальных данных и учетных данных".

Для локального тестирования разработки используйте средство Secret Manager для хранения секрета клиента серверного приложения под ключом Authentication:Schemes:MicrosoftOidc:ClientSecretконфигурации.

Примечание.

Если приложение использует идентификатор Microsoft Entra или Azure AD B2C, создайте секрет клиента в регистрации приложения в записи или портал Azure (управление>сертификатами и секретами>нового секрета клиента). Используйте значение нового секрета в следующем руководстве.

Пример приложения не был инициализирован для средства Диспетчера секретов. Используйте командную оболочку, например командную оболочку PowerShell разработчика в Visual Studio, чтобы выполнить следующую команду. Перед выполнением команды измените каталог с cd помощью команды на каталог проекта сервера. Команда устанавливает идентификатор секретов пользователя (<UserSecretsId> в файле проекта приложения сервера):

dotnet user-secrets init

Выполните следующую команду, чтобы задать секрет клиента. Заполнитель {SECRET} — это секрет клиента, полученный из регистрации приложения:

dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"

При использовании Visual Studio можно подтвердить, что секрет задан, щелкнув правой кнопкой мыши проект сервера в Обозреватель решений и выбрав "Управление секретами пользователей".

Настройка приложения

Следующая OpenIdConnectOptions конфигурация найдена в файле проекта Program по вызову AddOpenIdConnect:

  • SignInScheme: задает схему проверки подлинности, соответствующую ПО промежуточного слоя, ответственному за сохранение пользователей identity после успешной проверки подлинности. Обработчик OIDC должен использовать схему входа, которая может сохранять учетные данные пользователя в запросах. Следующая строка представлена лишь для демонстрационных целей. Если опущено, DefaultSignInScheme используется в качестве резервного значения.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Области для openid и (Scope) (необязательноopenid): области и profile profile области также настраиваются по умолчанию, так как они необходимы для работы обработчика OIDC, но их может потребоваться повторно добавить, если области включены в Authentication:Schemes:MicrosoftOidc:Scope конфигурацию. Общие рекомендации по настройке см. в разделе "Конфигурация" в ASP.NET Core и конфигурации ASP.NET CoreBlazor.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: определяет, следует ли хранить маркеры доступа и обновления в AuthenticationProperties после успешной авторизации. Это свойство устанавливается для false уменьшения размера конечной проверки подлинности cookie.

    oidcOptions.SaveTokens = false;
    
  • Область автономного доступа (Scope): offline_access область требуется для маркера обновления.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Authority и ClientId: задает идентификатор центра и клиента для вызовов OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Пример:

    • Центр (): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ ({AUTHORITY}использует идентификатор aaaabbbb-0000-cccc-1111-dddd2222eeeeклиента)
    • Идентификатор клиента ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
    

    Пример для центра "common" Microsoft Azure:

    Центр "common" должен использоваться для мультитенантных приложений. Вы также можете использовать центр "common" для однотенантных приложений, но это IssuerValidator необходимо, как показано далее в этом разделе.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ResponseType: настраивает обработчик OIDC только для выполнения потока кода авторизации. Неявные гранты и гибридные потоки являются ненужными в этом режиме.

    В конфигурации регистрации приложений приложений неявного предоставления или портал Azure портал Azure не установите флажок, чтобы конечная точка авторизации возвращала маркеры доступа или маркеры идентификатора. Обработчик OIDC автоматически запрашивает соответствующие маркеры с помощью кода, возвращаемого из конечной точки авторизации.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimsи настройка NameClaimType RoleClaimTypeи: многие серверы ClaimTypesOIDC используют "" и "namerole" вместо значений по умолчанию SOAP/WS-Fed. Если MapInboundClaims задано значение false, обработчик не выполняет сопоставления утверждений, а имена утверждений из JWT используются непосредственно приложением. В следующем примере для типа утверждения роли задано значение "roles", которое подходит для идентификатора Microsoft Entra (ME-ID). identity Дополнительные сведения см. в документации поставщика.

    Примечание.

    MapInboundClaims Необходимо задать значение false для большинства поставщиков OIDC, что предотвращает переименование утверждений.

    oidcOptions.MapInboundClaims = false;
    oidcOptions.TokenValidationParameters.NameClaimType = "name";
    oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
    
  • Конфигурация пути. Пути должны соответствовать URI перенаправления (путь обратного вызова для входа) и пути перенаправления после выхода (путь обратного вызова со знаком выхода), настроенные при регистрации приложения в поставщике OIDC. В портал Azure пути настраиваются в колонке проверки подлинности регистрации приложения. Пути входа и выхода должны быть зарегистрированы как URI перенаправления. Значения по умолчанию: /signin-oidc и /signout-callback-oidc.

    • CallbackPath: Путь запроса в базовом пути приложения, в котором возвращается агент пользователя.

      В записи или портал Azure задайте путь в URI перенаправления веб-платформы:

      https://localhost/signin-oidc

      Примечание.

      Порт не требуется для localhost адресов при использовании идентификатора Microsoft Entra. Большинству других поставщиков OIDC требуется правильный порт.

    • SignedOutCallbackPath: Путь запроса в базовом пути приложения, где агент пользователя возвращается после выхода из identity поставщика.

      В записи или портал Azure задайте путь в URI перенаправления веб-платформы:

      https://localhost/signout-callback-oidc

      Примечание.

      Порт не требуется для localhost адресов при использовании идентификатора Microsoft Entra. Большинству других поставщиков OIDC требуется правильный порт.

      Примечание.

      При использовании Microsoft Identity Web поставщик в настоящее время перенаправляется только в том SignedOutCallbackPath случае, если microsoftonline.com используется центр (https://login.microsoftonline.com/{TENANT ID}/v2.0/). Это ограничение не существует, если вы можете использовать центр "common" с Microsoft Identity Web. Дополнительные сведения см. в разделе postLogoutRedirectUri, если URL-адрес центра содержит идентификатор клиента (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: запросы, полученные по этому пути, приводят к вызову обработчика выхода с помощью схемы выхода.

      В записи или портал Azure задайте URL-адрес выхода front-channel:

      https://localhost/signout-oidc

      Примечание.

      Порт не требуется для localhost адресов при использовании идентификатора Microsoft Entra. Большинству других поставщиков OIDC требуется правильный порт.

      oidcOptions.CallbackPath = new PathString("{PATH}");
      oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
      oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
      

      Примеры (значения по умолчанию):

      oidcOptions.CallbackPath = new PathString("/signin-oidc");
      oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
      oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
      
  • (Microsoft Azure только с "общей" конечной точкой) TokenValidationParameters.IssuerValidator: многие поставщики OIDC работают с проверяющим элементом издателя по умолчанию, но нам нужно учитывать параметризуемый издателем идентификатор клиента ({TENANT ID}) возвращенный https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Дополнительные сведения см. в статье SecurityTokenInvalidIssuerException with OpenID Connect и конечная точка Azure AD common (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#1731).

    Только для приложений с помощью идентификатора Microsoft Entra или Azure AD B2C с конечной точкой common:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

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

Проверьте пример приложения для следующих функций:

  • Автоматическое обновление неинтерактивного маркера с помощью пользовательского cookie средства обновления (CookieOidcRefresher.cs).
  • Серверный проект вызывает AddAuthenticationStateSerialization добавление поставщика состояния проверки подлинности на стороне сервера, который используется PersistentComponentState для потока состояния проверки подлинности клиенту. Клиент вызывает AddAuthenticationStateDeserialization десериализацию и использует состояние проверки подлинности, переданное сервером. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.
  • Пример запросов к Blazor Web App данным о погоде обрабатывается минимальной конечной точкой API (/weather-forecast) в Program файле (Program.cs). Для конечной точки требуется авторизация путем вызова RequireAuthorization. Для всех контроллеров, добавляющихся в проект, добавьте [Authorize] атрибут в контроллер или действие.
  • Приложение безопасно вызывает (веб-) API в проекте сервера для погодных данных:
    • При отрисовке Weather компонента на сервере компонент используется ServerWeatherForecaster на сервере для получения данных о погоде напрямую (а не через вызов веб-API).
    • При отрисовке компонента на клиенте компонент использует ClientWeatherForecaster реализацию службы, которая использует предварительно настроенный HttpClient (в файле клиентского проекта Program ) вызов веб-API к проекту сервера. Минимальная конечная точка API (/weather-forecast), определенная в файле проекта Program сервера, получает данные о погоде из ServerWeatherForecaster клиента и возвращает данные клиенту.
  • Автоматическое обновление неинтерактивного маркера с помощью пользовательского cookie средства обновления (CookieOidcRefresher.cs).
  • Класс PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) — это серверная сторона AuthenticationStateProvider , которая используется PersistentComponentState для потока состояния проверки подлинности клиенту, который затем фиксируется в течение времени существования приложения WebAssembly.
  • Пример запросов к Blazor Web App данным о погоде обрабатывается минимальной конечной точкой API (/weather-forecast) в Program файле (Program.cs). Для конечной точки требуется авторизация путем вызова RequireAuthorization. Для всех контроллеров, добавляющихся в проект, добавьте [Authorize] атрибут в контроллер или действие.
  • Приложение безопасно вызывает (веб-) API в проекте сервера для погодных данных:
    • При отрисовке Weather компонента на сервере компонент используется ServerWeatherForecaster на сервере для получения данных о погоде напрямую (а не через вызов веб-API).
    • При отрисовке компонента на клиенте компонент использует ClientWeatherForecaster реализацию службы, которая использует предварительно настроенный HttpClient (в файле клиентского проекта Program ) вызов веб-API к проекту сервера. Минимальная конечная точка API (/weather-forecast), определенная в файле проекта Program сервера, получает данные о погоде из ServerWeatherForecaster клиента и возвращает данные клиенту.

Дополнительные сведения о вызовах API (веб-) с помощью абстракций служб см. в Blazor Web Appстатье "Вызов веб-API" из приложения ASP.NET CoreBlazor.

Клиентский Blazor Web App проект (BlazorWebAppOidc.Client)

Проект BlazorWebAppOidc.Client — это клиентский проект Blazor Web App.

Клиент вызывает AddAuthenticationStateDeserialization десериализацию и использует состояние проверки подлинности, переданное сервером. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.

Класс PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) — это клиентская сторона AuthenticationStateProvider , которая определяет состояние проверки подлинности пользователя путем поиска данных, сохраненных на странице при отрисовке на сервере. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.

Если пользователю нужно войти или выйти, требуется полная перезагрузка страницы.

Пример приложения предоставляет только имя пользователя и электронную почту в целях отображения. Он не включает маркеры, прошедшие проверку подлинности на сервере при выполнении последующих запросов, которые работают отдельно с помощью cookie включенного в HttpClient запросы к серверу.

Эта версия статьи охватывает реализацию OIDC с шаблоном Серверной части для frontend (BFF). Измените селектор версий статьи на OIDC без шаблона BFF, если спецификация приложения не вызывает внедрения шаблона BFF.

Рассматривается следующая спецификация:

  • Использует Blazor Web App режим автоматической отрисовки с глобальной интерактивностью.
  • Пользовательские службы поставщика состояний проверки подлинности используются сервером и клиентскими приложениями для записи состояния проверки подлинности пользователя и потока между сервером и клиентом.
  • Это приложение является отправной точкой для любого потока проверки подлинности OIDC. OIDC настраивается вручную в приложении и не зависит от идентификатора Microsoft Entra или веб-пакетов МайкрософтIdentity, а также не требует размещения Microsoft Azure. Однако пример приложения можно использовать с Entra, Microsoft Identity Web и размещаться в Azure.
  • Автоматическое обновление неинтерактивного маркера.
  • Шаблон серверной части внешнего интерфейса (BFF) используется .NET Aspire для обнаружения служб и YARP для прокси-запросов к конечной точке прогноза погоды в серверном приложении.
    • Внутренний веб-API использует проверку подлинности носителя JWT для проверки маркеров JWT, сохраненных Blazor Web App в входе cookie.
    • Aspire улучшает возможности создания облачных приложений .NET. Он предоставляет согласованный набор средств и шаблонов для создания и запуска распределенных приложений.
    • YARP (еще один обратный прокси-сервер) — это библиотека, используемая для создания обратного прокси-сервера.

Дополнительные сведения .NET Aspireсм. в статье "Общая доступность" : упрощение разработки .NET Aspire.NET Cloud-Native (май 2024 г.).

Предварительные требования

.NET Aspire требуется Visual Studio версии 17.10 или более поздней.

Пример приложения

Пример приложения состоит из пяти проектов:

  • .NET Aspire:
    • Aspire.AppHost: используется для управления проблемами оркестрации высокого уровня приложения.
    • Aspire.ServiceDefaults: содержит конфигурации приложений по умолчанию .NET Aspire , которые можно расширить и настроить по мере необходимости.
  • MinimalApiJwt: внутренний веб-API, содержащий пример конечной точки Минимального API для данных о погоде.
  • BlazorWebAppOidc: серверный проект объекта Blazor Web App.
  • BlazorWebAppOidc.Client: клиентский проект объекта Blazor Web App.

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

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

Проектов: .NET Aspire

Дополнительные сведения об использовании .NET Aspire и .ServiceDefaults .AppHost проектах примера приложения см. в .NET Aspire документации.

Убедитесь, что вы выполнили необходимые .NET Aspireусловия. Дополнительные сведения см. в разделе "Предварительные требования " краткого руководства. Создание первого .NET Aspire приложения.

Пример приложения настраивает только небезопасный профиль запуска HTTP (http) для использования во время тестирования разработки. Дополнительные сведения, включая пример небезопасных и безопасных профилей параметров запуска, см. в разделе "Разрешить небезопасный транспорт" (.NET Aspire.NET Aspireдокументация).

Серверный Blazor Web App проект (BlazorWebAppOidc)

Проект BlazorWebAppOidc является серверным проектом Blazor Web App. Проект использует YARP для прокси-запросов к конечной точке прогноза погоды в проекте внутреннего веб-API (MinimalApiJwt) с access_token сохраненным в проверке подлинности cookie.

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

Примечание.

Серверный проект используется, но никогда не используется IHttpContextAccessor/HttpContextдля интерактивных отрисованных компонентов. Дополнительные сведения см. в руководстве по устранению угроз для интерактивной отрисовки на стороне сервера ASP.NET CoreBlazor.

Настройка

В этом разделе объясняется, как настроить пример приложения.

Примечание.

Для идентификатора Microsoft Entra или Azure AD B2C можно использовать AddMicrosoftIdentityWebApp из Microsoft Identity Web (Microsoft.Identity.Web пакет NuGet, документация по API), которая добавляет обработчики OIDC и Cookie проверки подлинности с соответствующими значениями по умолчанию. Пример приложения и руководство в этом разделе не используют Microsoft Identity Web. В руководстве показано, как настроить обработчик OIDC вручную для любого поставщика OIDC. Дополнительные сведения о реализации Microsoft Identity Web см. в связанных ресурсах.

Установка секрета клиента

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

Не сохраняйте секреты приложений, строка подключения, учетные данные, пароли, персональные идентификационные номера (ПИН-коды), частный код C#/.NET или закрытые ключи и токены в клиентском коде, который всегда небезопасн. В средах тестирования и промежуточной и рабочей среды код на стороне Blazor сервера и веб-API должны использовать безопасные потоки проверки подлинности, которые не поддерживают учетные данные в файлах кода проекта или конфигурации. Вне локального тестирования разработки рекомендуется избегать использования переменных среды для хранения конфиденциальных данных, так как переменные среды не являются наиболее безопасным подходом. Для локального тестирования разработки средство Secret Manager рекомендуется для защиты конфиденциальных данных. Дополнительные сведения см. в разделе "Безопасное обслуживание конфиденциальных данных и учетных данных".

Для локального тестирования разработки используйте средство Secret Manager для хранения секрета клиента серверного приложения под ключом Authentication:Schemes:MicrosoftOidc:ClientSecretконфигурации.

Примечание.

Если приложение использует идентификатор Microsoft Entra или Azure AD B2C, создайте секрет клиента в регистрации приложения в записи или портал Azure (управление>сертификатами и секретами>нового секрета клиента). Используйте значение нового секрета в следующем руководстве.

Пример приложения не был инициализирован для средства Диспетчера секретов. Используйте командную оболочку, например командную оболочку PowerShell разработчика в Visual Studio, чтобы выполнить следующую команду. Перед выполнением команды измените каталог с cd помощью команды на каталог проекта сервера. Команда устанавливает идентификатор секретов пользователя (<UserSecretsId> в файле проекта приложения сервера):

dotnet user-secrets init

Выполните следующую команду, чтобы задать секрет клиента. Заполнитель {SECRET} — это секрет клиента, полученный из регистрации приложения:

dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"

При использовании Visual Studio можно подтвердить, что секрет задан, щелкнув правой кнопкой мыши проект сервера в Обозреватель решений и выбрав "Управление секретами пользователей".

Настройка приложения

Следующая OpenIdConnectOptions конфигурация найдена в файле проекта Program по вызову AddOpenIdConnect:

  • SignInScheme: задает схему проверки подлинности, соответствующую ПО промежуточного слоя, ответственному за сохранение пользователей identity после успешной проверки подлинности. Обработчик OIDC должен использовать схему входа, которая может сохранять учетные данные пользователя в запросах. Следующая строка представлена лишь для демонстрационных целей. Если опущено, DefaultSignInScheme используется в качестве резервного значения.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Области для openid и (Scope) (необязательноopenid): области и profile profile области также настраиваются по умолчанию, так как они необходимы для работы обработчика OIDC, но их может потребоваться повторно добавить, если области включены в Authentication:Schemes:MicrosoftOidc:Scope конфигурацию. Общие рекомендации по настройке см. в разделе "Конфигурация" в ASP.NET Core и конфигурации ASP.NET CoreBlazor.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: определяет, следует ли хранить маркеры доступа и обновления в AuthenticationProperties после успешной авторизации. Для проверки подлинности запросов о погоде из проектаMinimalApiJwt веб-API серверной части задано true значение.

    oidcOptions.SaveTokens = true;
    
  • Область автономного доступа (Scope): offline_access область требуется для маркера обновления.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Области получения данных о погоде из веб-API (Scope): область Weather.Get настраивается на портале Azure или Entra в разделе "Предоставление API". Это необходимо для проекта веб-API серверной части (MinimalApiJwt) для проверки маркера доступа с помощью носителя JWT.

    oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
    

    Пример:

    • URI идентификатора приложения ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
      • Имя каталога ({DIRECTORY NAME}): contoso
      • Идентификатор приложения (клиента) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    • Область, настроенная для данных о погоде (MinimalApiJwt{API NAME}):Weather.Get
    oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
    

    В предыдущем примере относится приложение, зарегистрированное в клиенте с типом клиента AAD B2C. Если приложение зарегистрировано в клиенте ME-ID, URI идентификатора приложения отличается, поэтому область отличается.

    Пример:

    • URI идентификатора приложения ({APP ID URI}): api://{CLIENT ID} с идентификатором приложения (клиентом) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    • Область, настроенная для данных о погоде (MinimalApiJwt{API NAME}):Weather.Get
    oidcOptions.Scope.Add("api://00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
    
  • Authority и ClientId: задает идентификатор центра и клиента для вызовов OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Пример:

    • Центр (): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ ({AUTHORITY}использует идентификатор aaaabbbb-0000-cccc-1111-dddd2222eeeeклиента)
    • Идентификатор клиента ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
    

    Пример для центра "common" Microsoft Azure:

    Центр "common" должен использоваться для мультитенантных приложений. Вы также можете использовать центр "common" для однотенантных приложений, но это IssuerValidator необходимо, как показано далее в этом разделе.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ResponseType: настраивает обработчик OIDC только для выполнения потока кода авторизации. Неявные гранты и гибридные потоки являются ненужными в этом режиме.

    В конфигурации регистрации приложений приложений неявного предоставления или портал Azure портал Azure не установите флажок, чтобы конечная точка авторизации возвращала маркеры доступа или маркеры идентификатора. Обработчик OIDC автоматически запрашивает соответствующие маркеры с помощью кода, возвращаемого из конечной точки авторизации.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimsи настройка NameClaimType RoleClaimTypeи: многие серверы ClaimTypesOIDC используют "" и "namerole" вместо значений по умолчанию SOAP/WS-Fed. Если MapInboundClaims задано значение false, обработчик не выполняет сопоставления утверждений, а имена утверждений из JWT используются непосредственно приложением. В следующем примере для типа утверждения роли задано значение "roles", которое подходит для идентификатора Microsoft Entra (ME-ID). identity Дополнительные сведения см. в документации поставщика.

    Примечание.

    MapInboundClaims Необходимо задать значение false для большинства поставщиков OIDC, что предотвращает переименование утверждений.

    oidcOptions.MapInboundClaims = false;
    oidcOptions.TokenValidationParameters.NameClaimType = "name";
    oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
    
  • Конфигурация пути. Пути должны соответствовать URI перенаправления (путь обратного вызова для входа) и пути перенаправления после выхода (путь обратного вызова со знаком выхода), настроенные при регистрации приложения в поставщике OIDC. В портал Azure пути настраиваются в колонке проверки подлинности регистрации приложения. Пути входа и выхода должны быть зарегистрированы как URI перенаправления. Значения по умолчанию: /signin-oidc и /signout-callback-oidc.

    • CallbackPath: Путь запроса в базовом пути приложения, в котором возвращается агент пользователя.

      В записи или портал Azure задайте путь в URI перенаправления веб-платформы:

      https://localhost/signin-oidc

      Примечание.

      Порт не требуется для localhost адресов.

    • SignedOutCallbackPath: Путь запроса в базовом пути приложения, где агент пользователя возвращается после выхода из identity поставщика.

      В записи или портал Azure задайте путь в URI перенаправления веб-платформы:

      https://localhost/signout-callback-oidc

      Примечание.

      Порт не требуется для localhost адресов.

      Примечание.

      При использовании Microsoft Identity Web поставщик в настоящее время перенаправляется только в том SignedOutCallbackPath случае, если microsoftonline.com используется центр (https://login.microsoftonline.com/{TENANT ID}/v2.0/). Это ограничение не существует, если вы можете использовать центр "common" с Microsoft Identity Web. Дополнительные сведения см. в разделе postLogoutRedirectUri, если URL-адрес центра содержит идентификатор клиента (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: запросы, полученные по этому пути, приводят к вызову обработчика выхода с помощью схемы выхода.

      В записи или портал Azure задайте URL-адрес выхода front-channel:

      https://localhost/signout-oidc

      Примечание.

      Порт не требуется для localhost адресов.

      oidcOptions.CallbackPath = new PathString("{PATH}");
      oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
      oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
      

      Примеры (значения по умолчанию):

      oidcOptions.CallbackPath = new PathString("/signin-oidc");
      oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
      oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
      
  • (Microsoft Azure только с "общей" конечной точкой) TokenValidationParameters.IssuerValidator: многие поставщики OIDC работают с проверяющим элементом издателя по умолчанию, но нам нужно учитывать параметризуемый издателем идентификатор клиента ({TENANT ID}) возвращенный https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Дополнительные сведения см. в статье SecurityTokenInvalidIssuerException with OpenID Connect и конечная точка Azure AD common (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#1731).

    Только для приложений с помощью идентификатора Microsoft Entra или Azure AD B2C с конечной точкой common:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

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

Проверьте пример приложения для следующих функций:

  • Автоматическое обновление неинтерактивного маркера с помощью пользовательского cookie средства обновления (CookieOidcRefresher.cs).
  • Серверный проект вызывает AddAuthenticationStateSerialization добавление поставщика состояния проверки подлинности на стороне сервера, который используется PersistentComponentState для потока состояния проверки подлинности клиенту. Клиент вызывает AddAuthenticationStateDeserialization десериализацию и использует состояние проверки подлинности, переданное сервером. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.
  • Запросы к Blazor Web App проекту веб-API серверной части (MinimalApiJwt). MapForwarderProgram В файле добавляется прямая пересылка HTTP-запросов, которые соответствуют указанному шаблону определенному назначению, используя конфигурацию по умолчанию для исходящего запроса, настраиваемые преобразования и HTTP-клиент по умолчанию:
    • При отрисовке Weather компонента на сервере компонент используется ServerWeatherForecaster для прокси-запроса на данные погоды с маркером доступа пользователя.
    • При отрисовке компонента на клиенте компонент использует ClientWeatherForecaster реализацию службы, которая использует предварительно настроенный HttpClient (в файле клиентского проекта Program ) вызов веб-API к проекту сервера. Минимальная конечная точка API (/weather-forecast), определенная в файле проекта Program сервера, преобразует запрос с маркером доступа пользователя для получения данных о погоде.
  • Автоматическое обновление неинтерактивного маркера с помощью пользовательского cookie средства обновления (CookieOidcRefresher.cs).
  • Класс PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) — это серверная сторона AuthenticationStateProvider , которая используется PersistentComponentState для потока состояния проверки подлинности клиенту, который затем фиксируется в течение времени существования приложения WebAssembly.
  • Запросы к Blazor Web App проекту веб-API серверной части (MinimalApiJwt). MapForwarderProgram В файле добавляется прямая пересылка HTTP-запросов, которые соответствуют указанному шаблону определенному назначению, используя конфигурацию по умолчанию для исходящего запроса, настраиваемые преобразования и HTTP-клиент по умолчанию:
    • При отрисовке Weather компонента на сервере компонент используется ServerWeatherForecaster для прокси-запроса на данные погоды с маркером доступа пользователя.
    • При отрисовке компонента на клиенте компонент использует ClientWeatherForecaster реализацию службы, которая использует предварительно настроенный HttpClient (в файле клиентского проекта Program ) вызов веб-API к проекту сервера. Минимальная конечная точка API (/weather-forecast), определенная в файле проекта Program сервера, преобразует запрос с маркером доступа пользователя для получения данных о погоде.

Дополнительные сведения о вызовах API (веб-) с помощью абстракций служб см. в Blazor Web Appстатье "Вызов веб-API" из приложения ASP.NET CoreBlazor.

Клиентский Blazor Web App проект (BlazorWebAppOidc.Client)

Проект BlazorWebAppOidc.Client — это клиентский проект Blazor Web App.

Клиент вызывает AddAuthenticationStateDeserialization десериализацию и использует состояние проверки подлинности, переданное сервером. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.

Класс PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) — это клиентская сторона AuthenticationStateProvider , которая определяет состояние проверки подлинности пользователя путем поиска данных, сохраненных на странице при отрисовке на сервере. Состояние проверки подлинности исправлено для времени существования приложения WebAssembly.

Если пользователю нужно войти или выйти, требуется полная перезагрузка страницы.

Пример приложения предоставляет только имя пользователя и электронную почту в целях отображения. Он не включает маркеры, прошедшие проверку подлинности на сервере при выполнении последующих запросов, которые работают отдельно с помощью cookie включенного в HttpClient запросы к серверу.

Проект веб-API серверной части (MinimalApiJwt)

Проект MinimalApiJwt — это внутренний веб-API для нескольких интерфейсных проектов. Проект настраивает минимальную конечную точку API для данных о погоде. Запросы из Blazor Web App серверного проекта (BlazorWebAppOidc) являются прокси-серверными MinimalApiJwt .

Настройка

Настройте проект в вызове в JwtBearerOptions AddJwtBearer файле проекта Program :

  • Audience: задает аудиторию для любого полученного маркера OpenID Connect.

    На портале Azure или Entra: соответствует значению только путь URI идентификатора приложения, настроенного при добавлении Weather.Get области в разделе "Предоставление API":

    jwtOptions.Audience = "{APP ID URI}";
    

    Пример:

    URI идентификатора приложения ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}

    • Имя каталога ({DIRECTORY NAME}): contoso
    • Идентификатор приложения (клиента) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    jwtOptions.Audience = "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444";
    

    В предыдущем примере относится приложение, зарегистрированное в клиенте с типом клиента AAD B2C. Если приложение зарегистрировано в клиенте ME-ID, URI идентификатора приложения отличается, поэтому аудитория отличается.

    Пример:

    URI идентификатора приложения ({APP ID URI}): api://{CLIENT ID} с идентификатором приложения (клиентом) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444

    jwtOptions.Audience = "api://00001111-aaaa-2222-bbbb-3333cccc4444";
    
  • Authority: задает центр для выполнения вызовов OpenID Connect. Соответствует значению центра, настроенного для обработчика OIDC в BlazorWebAppOidc/Program.cs:

    jwtOptions.Authority = "{AUTHORITY}";
    

    Пример:

    Центр (): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ ({AUTHORITY}использует идентификатор aaaabbbb-0000-cccc-1111-dddd2222eeeeклиента)

    jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    

    В предыдущем примере относится приложение, зарегистрированное в клиенте с типом клиента AAD B2C. Если приложение зарегистрировано в клиенте ME-ID, центр должен соответствовать issurer (iss) JWT, возвращаемого поставщиком identity :

    jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
    

Минимальный API для данных о погоде

Безопасная конечная точка данных прогноза Program погоды в файле проекта:

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

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

Добавление компонентов, которые применяют интерактивную отрисовку на стороне сервера

Так как приложение использует глобальную интерактивную автоматическую отрисовку с помощью Routes компонента, отдельные компоненты, которые указывают интерактивную отрисовку на стороне сервера (интерактивный SSR), @rendermode InteractiveServerв файле определения компонента (.razor) помещаются в папку .ClientпроектаPages.

Размещение интерактивных компонентов SSR в .Client проекте является контринтуитивным, так как такие компоненты отображаются только на сервере.

Если вы помещаете интерактивный компонент SSR в папку проекта Components/Pages сервера, компонент предварительно отображается в браузере пользователя. Тем не менее, клиентский маршрутизатор не может найти компонент, в конечном счете, в результате чего 404 — не найден в браузере.

Поэтому поместите интерактивные компоненты SSR в папку .Client проекта Pages .

Перенаправление home на страницу выхода

Когда пользователь перемещается по приложению, компонент (Layout/LogInOrOut.razor) задает скрытое поле для возвращаемого URL-адреса (ReturnUrl) значение текущего URL-адреса (currentURL).LogInOrOut Когда пользователь выходит из приложения, identity поставщик возвращает их на страницу, из которой они вышли.

Если пользователь выходит из безопасной страницы, он возвращается обратно на ту же безопасную страницу после выхода только для отправки через процесс проверки подлинности. Это поведение хорошо, если пользователям нужно часто переключать учетные записи. Однако альтернативная спецификация приложения может вызвать возвращение пользователя на страницу приложения home или на другую страницу после выхода. В следующем примере показано, как задать страницу приложения home в качестве URL-адреса возврата для операций выхода.

Важные изменения LogInOrOut компонента показаны в следующем примере. Нет необходимости указать скрытое поле для ReturnUrl набора home / страницы, так как это путь по умолчанию. IDisposable больше не реализуется. Больше NavigationManager не внедряется. Весь @code блок удаляется.

Layout/LogInOrOut.razor:

@using Microsoft.AspNetCore.Authorization

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout @context.User.Identity?.Name
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> 
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

Криптографический nonce

Nonce — это строковое значение, которое связывает сеанс клиента с маркером идентификатора для устранения атак воспроизведения.

Если во время разработки и тестирования проверки подлинности возникает ошибка, используйте новый сеанс браузера InPrivate/incognito для каждого тестового запуска, независимо от того, насколько мало внесенных изменений в приложение или тестового пользователя, так как устаревшие cookie данные могут привести к ошибке nonce. Дополнительные сведения см. в разделе "Файлы cookie" и "Данные сайта".

Не требуется или используется, если маркер обновления обменивается на новый маркер доступа. В примере приложения CookieOidcRefresher () намеренно задает значение OpenIdConnectProtocolValidator.RequireNonce false.CookieOidcRefresher.cs

Роли приложений для приложений, не зарегистрированных в Microsoft Entra (ME-ID)

Этот раздел относится к приложениям, которые не используют идентификатор Microsoft Entra (ME-ID) в качестве identity поставщика. Сведения о приложениях, зарегистрированных с помощью ME-ID, см. в разделе "Роли приложений, зарегистрированных в Microsoft Entra (ME-ID).

Настройте тип утверждения роли (TokenValidationParameters.RoleClaimType) в следующих OpenIdConnectOptions параметрах Program.cs:

oidcOptions.TokenValidationParameters.RoleClaimType = "{ROLE CLAIM TYPE}";

Для многих поставщиков OIDC identity тип утверждения роли имеет тип role. identity Проверьте документацию поставщика по правильному значению.

Замените UserInfo класс в BlazorWebAppOidc.Client проекте следующим классом.

UserInfo.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "role";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

На этом этапе Razor компоненты могут принимать авторизацию на основе ролей и политик. Роли приложения отображаются в role утверждениях, по одному утверждению для каждой роли.

Роли приложений для приложений, зарегистрированных в Microsoft Entra (ME-ID)

Используйте инструкции в этом разделе для реализации ролей приложений, групп безопасности ME-ID и встроенных ролей администратора ME-ID для приложений с помощью идентификатора Microsoft Entra ID (ME-ID).

Описанный в этом разделе подход настраивает ME-ID для отправки групп и ролей в заголовке проверки подлинности cookie . Если пользователи входят только в несколько групп безопасности и ролей, следующий подход должен работать для большинства платформ размещения без возникновения проблемы, когда заголовки слишком длинные, например с размещением IIS с ограничением длины заголовка по умолчанию 16 КБ ().MaxRequestBytes Если длина заголовка является проблемой из-за высокого уровня членства в группе или роли, мы рекомендуем не следовать инструкциям в этом разделе в пользу реализации Microsoft Graph для получения групп и ролей пользователя из ME-ID отдельно, подход, который не расширяет размер проверки подлинности cookie. Дополнительные сведения см. в разделе "Недопустимый запрос — слишком длинный запрос — сервер IIS" (dotnet/aspnetcore #57545).

Настройте тип утверждения роли (TokenValidationParameters.RoleClaimTypeв OpenIdConnectOptions Program.cs). Задайте для параметра значение roles:

oidcOptions.TokenValidationParameters.RoleClaimType = "roles";

Хотя вы не можете назначать роли группам без учетной записи ME-ID Premium, вы можете назначать роли пользователям и получать утверждения ролей для пользователей со стандартной учетной записью Azure. В этом разделе не требуется учетная запись ME-ID Premium.

При работе с каталогом по умолчанию следуйте инструкциям в статье "Добавление ролей приложения в приложение" и их получение в маркере (документация по me-ID) для настройки и назначения ролей. Если вы не работаете с каталогом по умолчанию, измените манифест приложения в портал Azure, чтобы вручную установить роли приложения в appRoles записи файла манифеста. Дополнительные сведения см. в разделе "Настройка утверждения роли" (документация по ME-ID).

Группы безопасности Azure пользователя приходят в groups утверждения, а встроенные назначения ролей администратора ME-ID пользователя приходят в известные утверждения () идентификаторов.wids Значения обоих типов утверждений представляют собой идентификаторы GUID. При получении приложением эти утверждения можно использовать для установления авторизации роли и политики в Razor компонентах.

В манифесте приложения в портал Azure задайте для атрибута groupMembershipClaims Allзначение . Значение All результатов в me-ID отправляет все группы безопасности и распространителя (утверждения) и роли (widsgroupsутверждения) вошедшего пользователя. Чтобы задать groupMembershipClaims атрибут, выполните следующие действия.

  1. Откройте регистрацию приложения в портал Azure.
  2. Выберите Управление>Манифест на панели сбоку.
  3. Найдите атрибут groupMembershipClaims.
  4. Задайте для значения All ("groupMembershipClaims": "All").
  5. Выберите кнопку Сохранить.

Замените UserInfo класс в BlazorWebAppOidc.Client проекте следующим классом.

UserInfo.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Security.Claims;

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }
    public required string[] Groups { get; init; }
    public required string[] Wids { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "roles";
    private const string GroupsClaimType = "groups";
    private const string WidsClaimType = "wids";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
            Groups = principal.FindAll(GroupsClaimType).Select(c => c.Value)
                .ToArray(),
            Wids = principal.FindAll(WidsClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat(Groups.Select(role => new Claim(GroupsClaimType, role)))
                .Concat(Wids.Select(role => new Claim(WidsClaimType, role)))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

На этом этапе Razor компоненты могут принимать авторизацию на основе ролей и политик:

  • Роли приложения отображаются в roles утверждениях, по одному утверждению для каждой роли.
  • Группы безопасности отображаются в groups утверждениях, по одному утверждению для каждой группы. Идентификаторы групп безопасности отображаются в портал Azure при создании группы безопасности и отображаются при выборе Identity>представления групп>обзора.>
  • Встроенные роли администратора ME-ID отображаются в wids утверждениях, по одному утверждению для каждой роли. Утверждение wids со значением b79fbf4d-3ef9-4689-8143-76b194e85509 всегда отправляется me-ID для не гостевых учетных записей клиента и не ссылается на роль администратора. Идентификаторы ролей администратора (идентификаторы шаблонов ролей) отображаются в портал Azure при выборе ролей и администраторов, а затем многоточие (...) >Описание указанной роли. Идентификаторы шаблонов ролей также перечислены в встроенных ролях Microsoft Entra (документация по Entra).

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

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

Серверное приложение — это стандартное приложение ASP.NET Core. Ознакомьтесь с руководством по ведению журнала ASP.NET Core, чтобы включить более низкий уровень ведения журнала в серверном приложении.

Чтобы включить ведение журнала отладки или трассировки для Blazor WebAssembly проверки подлинности, см. раздел Blazor ведения журнала проверки подлинности на стороне клиента ASP.NET Core с селектором версий статьи, установленным для ASP.NET Core 7.0 или более поздней версии.

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

  • Неправильная настройка приложения или поставщика Identity (IP)

    Наиболее частые ошибки вызваны неправильной настройкой. Ниже приводятся несколько примеров.

    • В зависимости от требований сценария, отсутствующие или неправильные элементы, такие как центр сертификации, экземпляр, идентификатор арендатора, домен арендатора, идентификатор клиента или URI перенаправления, не позволяют приложению осуществлять проверку подлинности клиентов.
    • Неверные области запросов не позволяют клиентам получать доступ к конечным точкам веб-API сервера.
    • Неправильные или отсутствующие разрешения API сервера не позволяют клиентам получить доступ к конечным точкам веб-API сервера.
    • Запуск приложения на порте, отличном от настроенного в URI перенаправления регистрации приложения IP-адреса. Обратите внимание, что порт не требуется для идентификатора Microsoft Entra и приложения, работающего на localhost адресе тестирования разработки, но конфигурация порта приложения и порт, на котором выполняется приложение, должно соответствовать не-адресамlocalhost .

    Покрытие конфигурации в этой статье показывает примеры правильной конфигурации. Тщательно проверьте конфигурацию, ищете неправильное настройку приложения и IP-адреса.

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

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

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

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

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

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

  • Несанкционированный клиент для ME-ID

    info: сбой авторизации Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]. Эти требования не выполнены: DenyAnonymousAuthorizationRequirement: требуется прошедший проверку подлинности пользователь.

    Ошибка обратного вызова входа из ME-ID:

    • Ошибка: unauthorized_client
    • Описание: AADB2C90058: The provided application is not configured to allow public clients.

    Чтобы устранить эту ошибку, сделайте следующее:

    1. На портале Azure перейдите к манифесту приложения.
    2. Задайте для атрибута allowPublicClient значение null или true.

Файлы 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.

Запуск серверного приложения

При тестировании и устранении Blazor Web Appнеполадок убедитесь, что приложение запущено из серверного проекта.

Проверка пользователя

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

UserClaims.razor:

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

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

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

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

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