Udostępnij za pośrednictwem


Konfigurowanie uwierzytelniania openID Connect Web (UI) w programie ASP.NET Core

Autor: Damien Bowden

Wyświetlanie lub pobieranie przykładowego kodu

W tym artykule opisano następujące obszary:

  • Co to jest poufny klient interakcyjny OpenID Connect
  • Tworzenie klienta OpenID Connect w programie ASP.NET Core
  • Przykłady klienta OpenID Connect z fragmentami kodu
  • Korzystanie z klientów dostawcy OpenID Connect innej firmy
  • Zaplecze dla architektury zabezpieczeń frontonu (BFF)
  • Zaawansowane funkcje, standardy, rozszerzanie klienta OpenID Connect

Aby uzyskać alternatywne środowisko korzystania z biblioteki uwierzytelniania Microsoft dla platformy .NET, Microsoft Identity Webi Microsoft Entra ID, zobacz przewodnik Szybki start : logowanie użytkowników i wywoływanie interfejsu API programu Microsoft Graph z ASP.NETcore aplikacji internetowej (dokumentacja platformy Azure).

Aby zapoznać się z przykładem korzystania z zewnętrznego serwera OIDC identyfikatora firmy Microsoft Entra, zobacz Logowanie użytkowników w przykładowej aplikacji webowej ASP.NET Core w zewnętrznym dzierżawcy oraz Aplikacja webowa ASP.NET Core uwierzytelniająca użytkowników przeciwko Microsoft Entra External ID za pomocą Microsoft Identity Web.

Co to jest poufny klient interakcyjny OpenID Connect

OpenID Connect może służyć do implementowania uwierzytelniania w aplikacjach ASP.NET Core. Zalecanym sposobem jest użycie poufnego klienta OpenID Connect przy użyciu przepływu kodu. W tej implementacji zaleca się użycie klucza dowodowego do wymiany kodu przez klientów publicznych OAuth (PKCE ). Zarówno klient aplikacji, jak i użytkownik aplikacji są uwierzytelniane w przepływie poufnym. Klient aplikacji używa wpisu tajnego klienta lub potwierdzenia klienta do uwierzytelniania.

Klienci public OpenID Connect/OAuth nie są już zalecane w przypadku aplikacji internetowych.

Domyślny przepływ działa, jak pokazano na poniższym diagramie:

Poufny klient przepływu kodu OIDC przy użyciu protokołu PKCE

Program OpenID Connect jest dostępny w wielu odmianach, a wszystkie implementacje serwera mają nieco inne parametry i wymagania. Niektóre serwery nie obsługują punktu końcowego informacji o użytkowniku, a niektóre nadal nie obsługują PKCE, a inne wymagają specjalnych parametrów w żądaniu tokenu. Asercji klienta można używać zamiast wpisów tajnych klienta. Istnieją również nowe standardy, które dodają dodatkowe zabezpieczenia na podstawie openID Connect Core, na przykład FAPI, CIBA lub DPoP dla podrzędnych interfejsów API.

Uwaga

Z platformy .NET 9 używany jest protokół OAuth 2.0 pushed authorization requests (PAR) RFC 9126 na wartość domyślną, jeśli serwer OpenID Connect obsługuje tę funkcję. Jest to przepływ trzech kroków, a nie przepływ dwuetapowy, jak pokazano powyżej. (Żądanie informacji o użytkowniku jest krokiem opcjonalnym).

Tworzenie klienta przepływu kodu Open ID Connect przy użyciu stron Razor

W poniższej sekcji pokazano, jak zaimplementować klienta OpenID Connect w pustym projekcie strony ASP.NET Core Razor . Tę samą logikę można zastosować do dowolnego projektu internetowego platformy ASP.NET Core, przy czym integracja interfejsu użytkownika jest inna.

Dodawanie obsługi programu OpenID Connect

Dodaj pakiety Microsoft.AspNetCore.Authentication.OpenIdConnect Nuget do projektu ASP.NET Core.

Konfigurowanie klienta OpenID Connect

Dodaj uwierzytelnianie do aplikacji internetowej, korzystając z builder.Services w pliku Program.cs. Konfiguracja jest zależna od serwera OpenID Connect. Każdy serwer OpenID Connect wymaga niewielkich różnic w konfiguracji.

Procedura obsługi OpenID Connect jest używana do wyzwań i wylogowyń. Element cookie służy do obsługi sesji w aplikacji internetowej. Schematy domyślne uwierzytelniania można określić zgodnie z wymaganiami.

Aby uzyskać więcej informacji, zobacz wskazówkidotyczące ASP.NET Core .

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";
});

Aby uzyskać szczegółowe informacje na temat różnych opcji programu OpenID Connect, zobacz Secure an ASP.NET Core Blazor Web App with OpenID Connect (OIDC).

Aby zapoznać się z różnymi możliwościami mapowania oświadczeń, zobacz Mapowanie, dostosowywanie i przekształcanie oświadczeń w usłudze ASP.NET Core.

Uwaga

Wymagane są następujące przestrzenie nazw:

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

Konfigurowanie właściwości konfiguracji

Dodaj ustawienia klienta OpenID Connect do właściwości konfiguracji aplikacji. Ustawienia muszą być zgodne z konfiguracją klienta na serwerze OpenID Connect. W ustawieniach aplikacji nie należy utrwalać żadnych tajemnic, ponieważ mogą zostać tam przypadkowo zapisane. Wpisy tajne powinny być przechowywane w bezpiecznej lokalizacji, takiej jak usługa Azure Key Vault w środowiskach produkcyjnych lub wpisów tajnych użytkownika w środowisku deweloperskim. Aby uzyskać więcej informacji, zobacz Bezpieczne przechowywanie sekretów aplikacji w środowisku developerskim w ASP.NET Core.

"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--"
},

Konfiguracja ścieżki wywołania zwrotnego wylogowanego

SignedOutCallbackPath (klucz konfiguracji: "SignedOutCallbackPath") jest ścieżką żądania w ścieżce podstawowej aplikacji przechwyconą przez program obsługi OpenID Connect, gdzie agent użytkownika jest najpierw przekierowywany po wylogowaniu się z dostawcy usług tożsamości. Przykładowa aplikacja nie ustawia wartości dla ścieżki, ponieważ jest używana domyślna wartość "/signout-callback-oidc". Po przechwyceniu żądania program obsługi OpenID Connect przekierowuje do SignedOutRedirectUri lub RedirectUri, jeśli jest to określone.

Skonfiguruj ścieżkę wywołania zwrotnego po wylogowaniu w rejestracji dostawcy OIDC aplikacji. W poniższym przykładzie symbol zastępczy {PORT} jest portem aplikacji:

https://localhost:{PORT}/signout-callback-oidc

Uwaga

W przypadku korzystania z identyfikatora Entra firmy Microsoft ustaw ścieżkę w konfiguracji platformyidentyfikatora URI przekierowania wpisów w witrynie Entra lub Azure Portal. Port nie jest wymagany dla adresów localhost w przypadku korzystania z usługi Entra. Większość innych dostawców OIDC wymaga poprawnego portu. Jeśli nie dodasz identyfikatora URI ścieżki wywołania zwrotnego wylogowania do rejestracji aplikacji w Entra, Entra odmówi przekierowania użytkownika z powrotem do aplikacji i jedynie poprosi ich o zamknięcie okna przeglądarki.

Zaktualizuj metodę potoku ASP.NET Core w klasie programu.

Przed metodą UseAuthorization należy zaimplementować metodę UseRouting.

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

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

Wymuszanie autoryzacji

Dodaj atrybut [Authorize] do chronionych stron Razor.

[Authorize]

Lepszym podejściem jest wymusić autoryzację dla całej aplikacji i zrezygnować z niezabezpieczonych stron:

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

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

Dodawanie nowych stron Logout.cshtml i SignedOut.cshtmlRazor do projektu

Konieczne jest wylogowanie zarówno z sesji cookie, jak i sesji OpenID Connect. Cała aplikacja musi zostać przekierowana na serwer OpenID Connect, aby się wylogować. Po pomyślnym wylogowaniu aplikacja otwiera trasę RedirectUri.

Zaimplementuj domyślną stronę wylogowania i zmień kod Logout razor na następujący:

[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 wymaga atrybutu [AllowAnonymous]:

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

Implementowanie strony Login

Można również zaimplementować stronę LoginRazor w celu wywołania ChallengeAsync bezpośrednio przy użyciu wymaganego AuthProperties. Nie jest to wymagane, jeśli aplikacja internetowa wymaga uwierzytelniania i jest używane domyślne wyzwanie.

Strona Login.cshtml wymaga atrybutu [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 };
    }
}

Dodawanie przycisku logowania i wylogowywanie użytkownika

@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>
}

Przykłady z fragmentami kodu

Przykład użycia punktu końcowego informacji o użytkowniku

Opcje openID Connect mogą służyć do mapowania oświadczeń, implementowania procedur obsługi, a nawet zapisywania tokenów w sesji na potrzeby późniejszego użycia.

Opcja Scope może służyć do żądania różnych roszczeń lub tokenu odświeżania, które są przesyłane jako informacja do serwera OpenID Connect. Żądanie offline_access nakazuje serwerowi zwrócenie tokenu odwołania, którego można użyć do odświeżenia sesji bez ponownej autoryzacji użytkownika aplikacji.

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";
});

Implementowanie dostawców tożsamości firmy Microsoft

Microsoft posiada wielu dostawców tożsamości i implementacje OpenID Connect. Firma Microsoft ma różne serwery OpenID Connect:

  • Microsoft Entra ID
  • Zewnętrzny identyfikator Microsoft Entra
  • Azure AD B2C

W przypadku uwierzytelniania przy użyciu jednego z dostawców tożsamości firmy Microsoft w programie ASP.NET Core zaleca się użycie pakietów Microsoft.Identity.Web Nuget.

Pakiety Microsoft.Identity.Web Nuget to określony klient firmy Microsoft oparty na kliencie ASP.NET Core OpenID Connect z pewnymi zmianami w kliencie domyślnym.

Korzystanie z klientów dostawcy OpenID Connect innej firmy

Wiele implementacji serwera OpenID Connect tworzy pakiety Nuget zoptymalizowane pod kątem tej samej implementacji openID Connect. Te pakiety implementują specyfikę klienta OpenID Connect z dodatkowymi wymaganymi przez określony serwer OpenID Connect. Microsoft.Identity.Web jest jednym z przykładów tego.

Jeśli w jednej aplikacji implementuje się wielu klientów OpenID Connect z różnych serwerów OpenID Connect, zwykle lepiej jest wrócić do domyślnej implementacji ASP.NET Core, ponieważ różni klienci zastępują niektóre opcje, co wpływa na innych klientów.

Dostawcy sieci Web OpenIddict to implementacja klienta, która obsługuje wiele różnych implementacji serwera.

IdentityModel to standardowa biblioteka pomocnika platformy .NET dla tożsamości opartej na oświadczeniach, OAuth 2.0 i OpenID Connect. Może to również pomóc w implementacji klienta.

Zaplecze dla architektury zabezpieczeń frontonu (BFF)

Nie zaleca się już implementowania klientów publicznych openID Connect dla wszystkich aplikacji internetowych.

Aby uzyskać więcej informacji, zobacz projekt OAuth 2.0 dla aplikacji Browser-Based .

W przypadku implementowania aplikacji internetowych , które nie mają niezależnego zaplecza, zalecamy użycie wzorca Backend for Frontend (BFF) architektury zabezpieczeń. Ten wzorzec można zaimplementować na różne sposoby, ale uwierzytelnianie jest zawsze implementowane w zapleczu i żadne poufne dane nie są wysyłane do klienta internetowego w celu uzyskania dalszej autoryzacji lub przepływów uwierzytelniania.

Zaawansowane funkcje, standardy, rozszerzanie klienta OIDC

Rejestrowanie

Debugowanie klientów OpenID Connect może być trudne. Dane osobowe nie są domyślnie rejestrowane. W przypadku debugowania w trybie programowania IdentityModelEventSource.ShowPII może służyć do rejestrowania poufnych danych osobowych. Nie wdrażaj aplikacji z IdentityModelEventSource.ShowPII na serwerach produkcyjnych.

//using ...

using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

//... code 

var app = builder.Build();

IdentityModelEventSource.ShowPII = true;

//... code 

app.Run();

Aby uzyskać więcej informacji, zobacz Logging.

Uwaga

Możesz chcieć obniżyć skonfigurowany poziom dziennika, aby wyświetlić wszystkie wymagane dzienniki.

Dostosowywanie parametrów OIDC i OAuth

Opcja obsługi uwierzytelniania przez programy OAuth i OIDC (AdditionalAuthorizationParameters) umożliwia dostosowanie parametrów komunikatów autoryzacji, które są zwykle dołączane jako część ciągu zapytania przekierowania.

Mapuj oświadczenia z openID Connect

Aby uzyskać więcej informacji, zobacz Mapowanie, dostosowywanie i przekształcanie oświadczeń w ASP.NET Core.

Blazor OpenID Connect

Aby uzyskać więcej informacji, zobacz Zabezpiecz aplikację ASP.NET Core Blazor Web App z użyciem OpenID Connect (OIDC).

Standardy