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


Настройка проверки подлинности OpenID Connect Web (UI) в ASP.NET Core

Дэмиен Боуден

Просмотреть или скачать образец кода

В этой статье рассматриваются следующие области:

  • Что такое конфиденциальный интерактивный клиент OpenID Connect
  • Создание клиента OpenID Connect в ASP.NET Core
  • Примеры клиента OpenID Connect с фрагментами кода
  • Использование сторонних клиентов поставщика OpenID Connect
  • Серверная часть для архитектуры безопасности внешнего интерфейса (BFF)
  • Расширенные функции, стандарты, расширение клиента OpenID Connect

Что такое конфиденциальный интерактивный клиент OpenID Connect

OpenID Connect можно использовать для реализации проверки подлинности в приложениях ASP.NET Core. Рекомендуется использовать конфиденциальный клиент OpenID Connect с помощью потока кода. Для этой реализации рекомендуется использовать ключ подтверждения для обмена кодом от общедоступных клиентов OAuth (PKCE). Клиент приложения и пользователь приложения проходят проверку подлинности в конфиденциальном потоке. Клиент приложения использует секрет клиента или утверждение клиента для проверки подлинности.

Общедоступные клиенты OpenID Connect/OAuth больше не рекомендуются для веб-приложений.

Поток по умолчанию работает, как показано на следующей схеме:

Конфиденциальный клиент потока кода OIDC с помощью PKCE

OpenID Connect поставляется во многих вариантах, и все реализации сервера имеют немного разные параметры и требования. Некоторые серверы не поддерживают конечную точку сведений о пользователе, некоторые по-прежнему не поддерживают PKCE и другие требуют специальных параметров в запросе маркера. Утверждения клиента можно использовать вместо секретов клиента. Новые стандарты также существуют, которые добавляют дополнительную безопасность поверх OpenID Connect Core, например FAPI, CIBA или DPoP для подчиненных API.

Примечание.

Из .NET 9 OAuth 2.0 Pushed Authorization Requests (PAR) RFC 9126 используется по умолчанию, если сервер OpenID Connect поддерживает это. Это три шага, а не два шага, как показано выше. (Запрос сведений о пользователе является необязательным шагом.)

Создание клиента потока кода Open ID Connect с помощью Razor Pages

В следующем разделе показано, как реализовать клиент OpenID Connect в пустом проекте страницы ASP.NET Core Razor . Та же логика может применяться к любому веб-проекту ASP.NET Core, но только интеграция пользовательского интерфейса отличается.

Добавление поддержки OpenID Connect

Добавьте пакеты Nuget Microsoft.AspNetCore.Authentication.OpenIdConnect в проект ASP.NET Core.

Настройка клиента OpenID Connect

Добавьте проверку подлинности в веб-приложение с помощью построителя. Службы в файле Program.cs . Конфигурация зависит от сервера OpenID Connect. Каждый сервер OpenID Connect требует небольших различий в настройке.

Обработчик OpenID Connect используется для проблем и выхода. Используется cookie для обработки сеанса в веб-приложении. Схемы по умолчанию для проверки подлинности можно указать по мере необходимости.

Дополнительные сведения см. в разделе ASP.NET Core [authentication-handler](xref: security/authentication/index?view=aspnetcore-8.0#authentication-handler).

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");

    options.Authority = oidcConfig["Authority"];
    options.ClientId = oidcConfig["ClientId"];
    options.ClientSecret = oidcConfig["ClientSecret"];

    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.MapInboundClaims = false;
    options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
    options.TokenValidationParameters.RoleClaimType = "roles";
});

Дополнительные сведения о различных параметрах OpenID Connect см. в разделе "Защита ASP.NET Core Blazor Web App с помощью OpenID Connect(OIDC ").

Сведения о сопоставлении, настройке и преобразовании утверждений в ASP.NET Core см. в разделе "Сопоставление", "Настройка" и преобразование утверждений в ASP.NET Core для различных возможностей сопоставления утверждений.

Примечание.

Требуются следующие пространства имен:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

Настройка свойств конфигурации

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

"OpenIDConnectSettings": {
  // OpenID Connect URL. (The base URL for the /.well-known/openid-configuration)
  "Authority": "<Authority>",
  // client ID from the OpenID Connect server
  "ClientId": "<Client ID>",
  //"ClientSecret": "--stored-in-user-secrets-or-key-vault--"
},

Обновите метод конвейера ASP.NET Core в классе программы.

Перед методом UseAuthorization необходимо реализовать UseRouting.

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
// Authorization is applied for middleware after the UseAuthorization method
app.UseAuthorization();
app.MapRazorPages();

Принудительное авторизация

Добавьте атрибут авторизации на защищенные razor страницы, например файл Index.cshtml.cs

[Authorize]

Лучшим способом будет принудительное авторизация всего приложения и отказ от небезопасных страниц

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

Добавление новой страницы Logout.cshtml и SignedOut.cshtml Razor в проект

Для выхода из сеанса и сеанса OpenID Connect требуется выход cookie . Все приложение должно перенаправиться на сервер OpenID Connect для выхода. После успешного выхода приложение откроет маршрут RedirectUri.

Реализуйте страницу выхода по умолчанию и измените код страницы выхода razor с помощью следующего:

[Authorize]
public class LogoutModel : PageModel
{
    public IActionResult OnGetAsync()
    {
        return SignOut(new AuthenticationProperties
        {
            RedirectUri = "/SignedOut"
        },
        // Clear auth cookie
        CookieAuthenticationDefaults.AuthenticationScheme,
        // Redirect to OIDC provider signout endpoint
        OpenIdConnectDefaults.AuthenticationScheme);
    }
}

Требуется SignedOut.cshtml атрибут AllowAnonymous.

[AllowAnonymous]
public class SignedOutModel : PageModel
{
    public void OnGet()
    {
    }
}

Реализация страницы входа

Страница входа Razor также может быть реализована для вызова ChallengeAsync напрямую с необходимыми authProperties. Это не обязательно, если для всего веб-приложения требуется проверка подлинности и используется задача по умолчанию.

Требуется login.cshtml атрибут AllowAnonymous.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPageOidc.Pages;

[AllowAnonymous]
public class LoginModel : PageModel
{
    [BindProperty(SupportsGet = true)]
    public string? ReturnUrl { get; set; }

    public async Task OnGetAsync()
    {
        var properties = GetAuthProperties(ReturnUrl);
        await HttpContext.ChallengeAsync(properties);
    }

    private static AuthenticationProperties GetAuthProperties(string? returnUrl)
    {
        const string pathBase = "/";

        // Prevent open redirects.
        if (string.IsNullOrEmpty(returnUrl))
        {
            returnUrl = pathBase;
        }
        else if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Relative))
        {
            returnUrl = new Uri(returnUrl, UriKind.Absolute).PathAndQuery;
        }
        else if (returnUrl[0] != '/')
        {
            returnUrl = $"{pathBase}{returnUrl}";
        }

        return new AuthenticationProperties { RedirectUri = returnUrl };
    }
}

Добавьте имя входа, кнопку выхода для пользователя.

@if (Context.User.Identity!.IsAuthenticated)
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
	</li>

	<span class="nav-link text-dark">Hi @Context.User.Identity.Name</span>
}
else
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Index">Login</a>
	</li>
}

Примеры с фрагментами кода

Пример использования конечной точки сведений пользователя

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

Параметр "Область" можно использовать для запроса различных утверждений или маркера обновления, который отправляется в качестве сведений на сервер OpenID Connect. Запрос offline_access запрашивает у сервера возврат эталонного маркера, который можно использовать для обновления сеанса без проверки подлинности пользователя приложения еще раз.

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
    options.Authority = oidcConfig["IdentityProviderUrl"];
    options.ClientSecret = oidcConfig["ClientSecret"];
    options.ClientId = oidcConfig["Audience"];
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.Scope.Add("offline_access");

    options.ClaimActions.Remove("amr");
    options.ClaimActions.MapUniqueJsonKey("website", "website");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    // .NET 9 feature
    options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Require;

    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "role";
});

Реализация поставщиков Майкрософт identity

Корпорация Майкрософт имеет несколько identity поставщиков и реализации OpenID Connect. Корпорация Майкрософт имеет разные серверы OpenID Connect:

  • Microsoft Entra ID
  • Внешний идентификатор Microsoft Entra
  • Azure AD B2C

При проверке подлинности с помощью одного из поставщиков Майкрософт identity в ASP.NET Core рекомендуется использовать Microsoft.Identity. Пакеты Web Nuget.

Microsoft.Identity. Пакеты Web Nuget — это конкретный клиент Майкрософт, созданный на основе клиента ASP.NET Core OpenID Connect с некоторыми изменениями в клиенте по умолчанию.

Использование сторонних клиентов поставщика OpenID Connect

Многие реализации сервера OpenID Connect создают пакеты Nuget, оптимизированные для той же реализации OpenID Connect. Эти пакеты реализуют особенности клиента OpenID Connect с дополнительными компонентами, необходимыми для конкретного сервера OpenID Connect. Microsoft.Identity. Интернет является одним из примеров этого.

При реализации нескольких клиентов OpenID Connect из разных серверов OpenID Connect в одном приложении обычно лучше вернуться к реализации по умолчанию ASP.NET Core, так как разные клиенты перезаписывают некоторые параметры, влияющие на другие клиенты.

Веб-поставщики OpenIddict — это клиентская реализация, которая поддерживает множество различных реализаций сервера.

IdentityModel — это справочная библиотека .NET standard для утверждений identity, OAuth 2.0 и OpenID Connect. Это также можно использовать для поддержки реализации клиента.

Серверная часть для архитектуры безопасности внешнего интерфейса (BFF)

Для любых веб-приложений больше не рекомендуется реализовать общедоступные клиенты OpenID Connect.

Дополнительные сведения см. в черновике OAuth 2.0 для приложений на основе браузера.

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

Расширенные функции, стандарты, расширение клиента OIDC

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

Отладка клиентов OpenID Connect может быть сложной. Персональные данные (PII) по умолчанию не регистрируются. При отладке в режиме разработки можно использовать идентификатор ** IdentityModelEventSource.ShowPII** для регистрации конфиденциальных персональных данных. Это никогда не должно быть развернуто на продуктивных серверах.

//using ...

using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

//... code 

var app = builder.Build();

IdentityModelEventSource.ShowPII = true;

//... code 

app.Run();

Дополнительные сведения о ведении журнала см. в разделе "Ведение журнала ".

Примечание.

Возможно, потребуется снизить настроенный уровень журнала, чтобы просмотреть все необходимые журналы.

Настройка OIDC и параметра OAuth

Параметр обработчиков AdditionalAuthorizationParameters проверки подлинности OAuth и OIDC позволяет настраивать параметры сообщения авторизации, которые обычно включаются в строку запроса перенаправления.

Сопоставление утверждений из OpenID Connect

См. следующий документ:

Сопоставление, настройка и преобразование утверждений в ASP.NET Core

Blazor OpenID Connect

См. следующий документ:

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

стандарты

OpenID Connect 1.0

Ключ подтверждения для обмена кодом с помощью общедоступных клиентов OAuth

Платформа авторизации OAuth 2.0

OAuth 2.0 Pushed Authorization Requests (PAR) RFC 9126