Jak użyć Identity do zabezpieczenia zaplecza internetowego interfejsu API dla SPA
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję artykułu dla .NET 9.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję artykułu dla .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję artykułu dla .NET 9.
ASP.NET Core Identity udostępnia interfejsy API obsługujące uwierzytelnianie, autoryzację i zarządzanie tożsamościami. Interfejsy API umożliwiają zabezpieczanie punktów końcowych zaplecza interfejsu internetowego API przy użyciu uwierzytelniania opartego na cookie. Opcja oparta na tokenach jest dostępna dla klientów, którzy nie mogą używać plików cookie, ale w tym celu ponosisz odpowiedzialność za zapewnienie bezpieczeństwa tokenów. Zalecamy używanie plików cookie dla aplikacji opartych na przeglądarce, ponieważ domyślnie przeglądarka automatycznie obsługuje je bez uwidaczniania ich w języku JavaScript.
W tym artykule pokazano, jak używać Identity do zabezpieczania zaplecza internetowego interfejsu API dla aplikacji typu SPA, takich jak Angular, React i Vue. Te same interfejsy API zaplecza mogą służyć do zabezpieczania Blazor WebAssembly aplikacji.
Wymagania wstępne
W tym artykule przedstawiono kroki, które umożliwiają dodanie uwierzytelniania i autoryzacji dla aplikacji ASP.NET Core Web API, która:
- Nie jest jeszcze skonfigurowany do uwierzytelniania.
- Obiekty docelowe
net8.0
lub nowsze. - Może to być API minimalne lub oparte na kontrolerze.
Niektóre instrukcje testowe w tym artykule korzystają z Swagger UI zawartego w szablonie projektu. Nie jest wymagany interfejs użytkownika Swagger do użycia Identity z backendem Web API.
Instalowanie pakietów NuGet
Zainstaluj następujące pakiety NuGet:
-
Microsoft.AspNetCore.Identity.EntityFrameworkCore
— Umożliwia Identity pracę z programem Entity Framework Core (EF Core). - Taki, który umożliwia EF Core pracę z bazą danych, taką jak jeden z następujących pakietów:
Aby uzyskać najszybszy sposób rozpoczęcia pracy, użyj bazy danych w pamięci.
Zmień bazę danych później na SQLite lub SQL Server, aby zapisać dane użytkownika między sesjami podczas testowania lub użycia produkcyjnego. Wprowadza to pewną złożoność w porównaniu z pamięcią w RAM, ponieważ wymaga utworzenia bazy danych za pośrednictwem migracji, jak pokazano w samouczku EF Core dla początkujących.
Zainstaluj te pakiety przy użyciu menedżera pakietów NuGet w programie Visual Studio lub polecenia dotnet add package CLI.
Utwórz IdentityDbContext
Dodaj klasę o nazwie ApplicationDbContext
, która dziedziczy z klasy IdentityDbContext<TUser>:
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
base(options)
{ }
}
Pokazany kod udostępnia specjalny konstruktor, który umożliwia skonfigurowanie bazy danych dla różnych środowisk.
Dodaj jedną lub więcej z poniższych dyrektyw using
zgodnie z potrzebami podczas dodawania kodu pokazanego w poniższych krokach.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
Skonfiguruj EF Core kontekst
Jak wspomniano wcześniej, najprostszym sposobem rozpoczęcia pracy jest użycie bazy danych w pamięci. W przypadku uruchamiania w pamięci każde uruchomienie rozpoczyna się od nowej bazy danych i nie ma potrzeby używania migracji. Po wywołaniu metody WebApplication.CreateBuilder(args)
, dodaj następujący kod, aby skonfigurować Identity do używania bazy danych w pamięci:
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseInMemoryDatabase("AppDb"));
Aby zapisać dane użytkownika między sesjami podczas testowania lub użycia produkcyjnego, zmień bazę danych później na SQLite lub SQL Server.
Dodawanie Identity usług do kontenera
Po wywołaniu WebApplication.CreateBuilder(args)
wywołaj AddAuthorization, aby dodać usługi do kontenera wstrzykiwania zależności (DI).
builder.Services.AddAuthorization();
Aktywuj Identity interfejsy API
Po wywołaniu WebApplication.CreateBuilder(args)
, wywołaj AddIdentityApiEndpoints<TUser>(IServiceCollection) i AddEntityFrameworkStores<TContext>(IdentityBuilder).
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Domyślnie zarówno pliki cookie, jak i zastrzeżone tokeny są aktywowane. Jeśli w punkcie końcowym logowania parametr ciągu zapytania useCookies
jest true
, pliki cookie i tokeny są wystawiane podczas logowania.
Mapuj Identity trasy
Po wywołaniu builder.Build()
, wywołaj MapIdentityApi<TUser>(IEndpointRouteBuilder), aby zmapować punkty końcowe Identity.
app.MapIdentityApi<IdentityUser>();
Zabezpieczanie wybranych punktów końcowych
Aby zabezpieczyć punkt końcowy, użyj RequireAuthorization metody rozszerzenia w wywołaniu Map{Method}
definiującym trasę. Na przykład:
app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
})
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();
Metody RequireAuthorization
można również użyć do:
Zabezpieczanie endpointów interfejsu użytkownika Swagger, jak pokazano w poniższym przykładzie:
app.MapSwagger().RequireAuthorization();
Zabezpiecz się przy użyciu określonego oświadczenia lub uprawnienia, jak pokazano w poniższym przykładzie:
.RequireAuthorization("Admin");
W projekcie internetowego interfejsu API opartego na kontrolerze zabezpiecz punkty końcowe, stosując atrybut [Authorize
] do kontrolera lub akcji.
Testowanie interfejsu API
Szybkim sposobem testowania uwierzytelniania jest użycie bazy danych w pamięci i interfejsu użytkownika programu Swagger dołączonego do szablonu projektu. W poniższych krokach pokazano, jak przetestować API za pomocą Swagger UI. Upewnij się, że punkty końcowe Swagger UI nie są zabezpieczone.
Próba uzyskania dostępu do zabezpieczonego punktu końcowego
- Uruchom aplikację i przejdź do interfejsu użytkownika programu Swagger.
- Rozwiń zabezpieczony punkt końcowy, taki jak
/weatherforecast
w projekcie utworzonym z szablonu web API. - Wybierz pozycję Wypróbuj.
- Wybierz polecenie Wykonaj. Odpowiedź to
401 - not authorized
.
Rejestracja na test
Rozwiń
/register
i wybierz pozycję Wypróbuj.W sekcji Parametry interfejsu użytkownika jest wyświetlana przykładowa treść żądania:
{ "email": "string", "password": "string" }
Zastąp ciąg prawidłowym adresem e-mail i hasłem, a następnie wybierz pozycję Wykonaj.
Aby zachować zgodność z domyślnymi regułami sprawdzania poprawności haseł, hasło musi mieć długość co najmniej sześciu znaków i zawierać co najmniej jeden z następujących znaków:
- Wielka litera
- Mała litera
- Cyfra liczbowa
- Znak niealfanumeryczny
Jeśli wprowadzisz nieprawidłowy adres e-mail lub nieprawidłowe hasło, wynik zawiera błędy walidacji. Oto przykład treści odpowiedzi z błędami walidacji:
{ "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1", "title": "One or more validation errors occurred.", "status": 400, "errors": { "PasswordTooShort": [ "Passwords must be at least 6 characters." ], "PasswordRequiresNonAlphanumeric": [ "Passwords must have at least one non alphanumeric character." ], "PasswordRequiresDigit": [ "Passwords must have at least one digit ('0'-'9')." ], "PasswordRequiresLower": [ "Passwords must have at least one lowercase ('a'-'z')." ] } }
Błędy są zwracane w formacie ProblemDetails , aby klient mógł je analizować i wyświetlać błędy walidacji zgodnie z potrzebami.
Pomyślna rejestracja powoduje
200 - OK
odpowiedź.
Testowanie logowania
Rozwiń
/login
i wybierz pozycję Wypróbuj. Przykładowa treść żądania zawiera dwa dodatkowe parametry:{ "email": "string", "password": "string", "twoFactorCode": "string", "twoFactorRecoveryCode": "string" }
Dodatkowe właściwości JSON nie są potrzebne w tym przykładzie i można je usunąć. Ustaw wartość opcji
useCookies
natrue
.Zastąp ciąg adresem e-mail i hasłem, których użyłeś podczas rejestracji, a następnie wybierz pozycję Wykonaj.
Pomyślne zalogowanie powoduje otrzymanie
200 - OK
odpowiedzi z nagłówkiem odpowiedzi cookie.
Ponowne testowanie zabezpieczonego punktu końcowego
Po pomyślnym zalogowaniu uruchom ponownie zabezpieczony punkt końcowy. Uwierzytelnianie cookie jest wysyłane automatycznie z żądaniem, a punkt końcowy jest autoryzowany. Cookie-oparte uwierzytelnianie jest bezpiecznie wbudowane w przeglądarkę i działa bez problemu.
Testowanie z użyciem klientów nieprzeglądarkowych
Niektórzy klienci sieci Web mogą domyślnie nie dołączać plików cookie do nagłówka:
Jeśli używasz narzędzia do testowania interfejsów API, może być konieczne włączenie plików cookie w ustawieniach.
Interfejs API języka JavaScript
fetch
domyślnie nie zawiera plików cookie. Włącz je, ustawiając w opcjachcredentials
na wartośćinclude
.Uruchomienie
HttpClient
aplikacji Blazor WebAssembly wymagaHttpRequestMessage
uwzględnienia poświadczeń, takich jak w poniższym przykładzie:request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
Korzystanie z uwierzytelniania opartego na tokenach
Zalecamy używanie plików cookie w aplikacjach opartych na przeglądarce, ponieważ domyślnie przeglądarka automatycznie obsługuje je bez ujawniania ich w języku JavaScript.
Wystawiono token niestandardowy (zastrzeżony dla platformy tożsamości ASP.NET Core), który może służyć do uwierzytelniania kolejnych żądań. Token jest przekazywany w nagłówku Authorization
jako token elementu nośnego. Dostarczany jest również token odświeżania. Ten token umożliwia aplikacji żądanie nowego tokenu po wygaśnięciu starego tokenu bez wymuszania ponownego zalogowania się użytkownika.
Tokeny nie są standardowymi tokenami internetowymi JSON (JWTs). Użycie tokenów niestandardowych jest zamierzone, ponieważ wbudowany Identity interfejs API jest przeznaczony głównie dla prostych scenariuszy. Opcja tokenu nie ma być w pełni funkcjonalnym dostawcą usług tożsamości lub serwerem tokenów, ale zamiast tego alternatywą dla cookie opcji dla klientów, którzy nie mogą używać plików cookie.
Aby użyć uwierzytelniania opartego na tokenach, ustaw parametr ciągu zapytania useCookies
na false
podczas wywoływania punktu końcowego /login
. Tokeny używają schematu uwierzytelniania bearer. Użycie tokenu zwróconego z wywołania do /login
, kolejne wywołania chronionych punktów końcowych powinny dodać nagłówek Authorization: Bearer <token>
, w którym <token>
znajduje się token dostępu. Aby uzyskać więcej informacji, zobacz Używanie punktu końcowego POST /login
w dalszej części tego artykułu.
Wyloguj się
Aby umożliwić użytkownikowi wylogowanie się, zdefiniuj /logout
punkt końcowy podobny do następującego przykładu:
app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
[FromBody] object empty) =>
{
if (empty != null)
{
await signInManager.SignOutAsync();
return Results.Ok();
}
return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();
Podaj pusty obiekt JSON ({}
) w treści żądania podczas wywoływania tego punktu końcowego. Poniższy kod to przykład wywołania punktu końcowego wylogowania:
public signOut() {
return this.http.post('/logout', {}, {
withCredentials: true,
observe: 'response',
responseType: 'text'
Punkty MapIdentityApi<TUser>
końcowe
Wywołanie MapIdentityApi<TUser>
dodaje następujące punkty końcowe do aplikacji:
POST /register
POST /login
POST /refresh
GET /confirmEmail
POST /resendConfirmationEmail
POST /forgotPassword
POST /resetPassword
POST /manage/2fa
GET /manage/info
POST /manage/info
Użyj punktu końcowego POST /register
Treść żądania musi zawierać właściwości Email i Password.
{
"email": "string",
"password": "string",
}
Aby uzyskać więcej informacji, zobacz:
- Rejestracja testowa wcześniej w tym artykule.
- RegisterRequest.
Użyj punktu końcowego POST /login
W treści żądania, Email i Password są wymagane. Jeśli włączono uwierzytelnianie dwuskładnikowe (2FA), wymagane jest albo TwoFactorCode, albo TwoFactorRecoveryCode. Jeśli 2FA nie jest włączone, pomiń zarówno twoFactorCode
, jak i twoFactorRecoveryCode
. Aby uzyskać więcej informacji, zobacz Używanie punktu końcowego POST /manage/2fa
w dalszej części tego artykułu.
Oto przykład treści żądania z wyłączonym uwierzytelnianiem dwuetapowym 2FA:
{
"email": "string",
"password": "string"
}
Oto przykłady treści żądań z włączoną usługą 2FA:
-
{ "email": "string", "password": "string", "twoFactorCode": "string", }
-
{ "email": "string", "password": "string", "twoFactorRecoveryCode": "string" }
Punkt końcowy oczekuje parametru ciągu zapytania:
-
useCookies
- Ustaw natrue
wartość dla uwierzytelniania opartego na cookie. Ustaw nafalse
lub pomiń dla uwierzytelniania opartego na tokenach.
Aby uzyskać więcej informacji na temat uwierzytelniania opartego na cookieprotokole, zobacz Testowanie logowania we wcześniejszej sekcji tego artykułu.
Uwierzytelnianie oparte na tokenach
Jeśli useCookies
pasuje do false
lub zostanie pominięte, jest włączone uwierzytelnianie oparte na tokenach. Treść odpowiedzi zawiera następujące właściwości:
{
"tokenType": "string",
"accessToken": "string",
"expiresIn": 0,
"refreshToken": "string"
}
Aby uzyskać więcej informacji na temat tych właściwości, zobacz AccessTokenResponse.
Umieść token dostępu w nagłówku, aby wysyłać uwierzytelnione żądania, jak pokazano w poniższym przykładzie
Authorization: Bearer {access token}
Gdy ten token dostępu ma wkrótce wygasnąć, wywołaj interfejs /refresh.
Użyj punktu końcowego POST /refresh
Do użycia tylko w przypadku uwierzytelniania opartego na tokenach. Pobiera nowy token dostępu bez wymuszania ponownego logowania użytkownika. Wywołaj ten punkt końcowy, gdy token dostępu wkrótce wygaśnie.
Treść żądania zawiera tylko element RefreshToken. Oto przykład treści żądania:
{
"refreshToken": "string"
}
Jeśli wywołanie zakończy się pomyślnie, treść odpowiedzi to nowy AccessTokenResponseelement, jak pokazano w poniższym przykładzie.
{
"tokenType": "string",
"accessToken": "string",
"expiresIn": 0,
"refreshToken": "string"
}
Użyj punktu końcowego GET /confirmEmail
Jeśli Identity jest skonfigurowany do potwierdzenia wiadomości e-mail, pomyślne wywołanie punktu końcowego /register
spowoduje wysłanie wiadomości e-mail zawierającej link do punktu końcowego /confirmEmail
. Link zawiera następujące parametry ciągu zapytania:
userId
code
-
changedEmail
- Uwzględnione tylko wtedy, gdy użytkownik zmienił adres e-mail podczas rejestracji.
Identity Zawiera domyślny tekst wiadomości e-mail z potwierdzeniem. Domyślnie temat wiadomości e-mail to "Potwierdź wiadomość e-mail", a treść wiadomości e-mail wygląda następująco:
Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.
RequireConfirmedEmail Jeśli właściwość jest ustawiona na true
, użytkownik nie może się zalogować, dopóki adres e-mail nie zostanie potwierdzony, klikając link w wiadomości e-mail. Punkt /confirmEmail
końcowy:
- Potwierdza adres e-mail i umożliwia użytkownikowi logowanie się.
- Zwraca tekst "Dziękujemy za potwierdzenie wiadomości e-mail" w treści odpowiedzi.
Aby skonfigurować Identity do potwierdzania wiadomości e-mail, dodaj kod w Program.cs
, aby ustawić RequireConfirmedEmail
na true
i dodaj klasę, która implementuje IEmailSender do kontenera Iniekcji Zależności. Na przykład:
builder.Services.Configure<IdentityOptions>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
});
builder.Services.AddTransient<IEmailSender, EmailSender>();
Aby uzyskać więcej informacji, zobacz Potwierdzanie konta i odzyskiwanie hasła w usłudze ASP.NET Core.
Identity Udostępnia domyślny tekst dla innych wiadomości e-mail, które należy również wysłać, na przykład w przypadku uwierzytelniania 2FA i resetowania hasła. Aby dostosować te wiadomości e-mail, podaj niestandardową implementację interfejsu IEmailSender
. W poprzednim przykładzie EmailSender
jest klasą, która implementuje IEmailSender
. Aby uzyskać więcej informacji, w tym przykład klasy, która implementuje IEmailSender
, zobacz Potwierdzanie konta i odzyskiwanie hasła w ASP.NET Core.
Użyj punktu końcowego POST /resendConfirmationEmail
Wysyła wiadomość e-mail tylko wtedy, gdy adres jest prawidłowy dla zarejestrowanego użytkownika.
Treść żądania zawiera tylko element Email. Oto przykład treści żądania:
{
"email": "string"
}
Aby uzyskać więcej informacji, zobacz sekcję Używanie punktu końcowego GET /confirmEmail
wcześniej w tym artykule.
Użyj punktu końcowego POST /forgotPassword
Generuje wiadomość e-mail zawierającą kod resetowania hasła. Wyślij ten kod na /resetPassword
adres przy użyciu nowego hasła.
Treść żądania zawiera tylko element Email. Oto przykład:
{
"email": "string"
}
Aby uzyskać informacje o tym, jak włączyć Identity do wysyłania wiadomości e-mail, zobacz Jak korzystać z punktu końcowegoGET /confirmEmail
.
Użyj punktu końcowego POST /resetPassword
Wywołaj ten punkt końcowy po wywołaniu punktu końcowego /forgotPassword
i otrzymaniu kodu resetowania.
Treść żądania wymaga Email, ResetCode oraz NewPassword. Oto przykład:
{
"email": "string",
"resetCode": "string",
"newPassword": "string"
}
Użyj punktu końcowego POST /manage/2fa
Konfiguruje uwierzytelnianie dwuskładnikowe (2FA) dla użytkownika. Po włączeniu uwierzytelniania 2FA, pomyślne logowanie wymaga kodu wygenerowanego przez aplikację uwierzytelniającą, oprócz adresu e-mail i hasła.
Włącz 2FA
Aby włączyć uwierzytelnianie 2FA dla aktualnie uwierzytelnioowanego użytkownika:
Wywołaj endpoint
/manage/2fa
, przesyłając pusty obiekt JSON ({}
) w treści żądania.Treść odpowiedzi udostępnia SharedKey wraz z innymi właściwościami, które nie są obecnie potrzebne. Klucz wspólny służy do konfigurowania aplikacji authenticator. Przykład treści odpowiedzi:
{ "sharedKey": "string", "recoveryCodesLeft": 0, "recoveryCodes": null, "isTwoFactorEnabled": false, "isMachineRemembered": false }
Użyj klucza współużytkowanego, aby uzyskać jednorazowe hasło oparte na czasie (TOTP). Aby uzyskać więcej informacji, zobacz Enable QR code generation for TOTP authenticator apps in ASP.NET Core (Włączanie generowania kodu QR dla aplikacji uwierzytelniania TOTP w usłudze ASP.NET Core).
Wywołaj punkt dostępu
/manage/2fa
, wysyłając kod TOTP i"enable": true
w treści żądania. Na przykład:{ "enable": true, "twoFactorCode": "string" }
Treść odpowiedzi potwierdza, że IsTwoFactorEnabled ma wartość true i udostępnia element RecoveryCodes. Kody odzyskiwania są używane do logowania się, gdy aplikacja uwierzytelniająca nie jest dostępna. Przykład treści odpowiedzi po pomyślnym włączeniu uwierzytelniania 2FA:
{ "sharedKey": "string", "recoveryCodesLeft": 10, "recoveryCodes": [ "string", "string", "string", "string", "string", "string", "string", "string", "string", "string" ], "isTwoFactorEnabled": true, "isMachineRemembered": false }
Logowanie przy użyciu uwierzytelniania 2FA
Wywołaj punkt końcowy /login
, przesyłając adres e-mail, hasło i TOTP w treści żądania. Na przykład:
{
"email": "string",
"password": "string",
"twoFactorCode": "string"
}
Jeśli użytkownik nie ma dostępu do aplikacji uwierzytelniającej, zaloguj się, korzystając z punktu końcowego /login
przy użyciu jednego z kodów odzyskiwania dostarczonych w momencie aktywacji 2FA. Treść żądania wygląda podobnie do następującego przykładu:
{
"email": "string",
"password": "string",
"twoFactorRecoveryCode": "string"
}
Resetowanie kodów odzyskiwania
Aby uzyskać nową kolekcję kodów odzyskiwania, wywołaj ten punkt końcowy z ustawieniem ResetRecoveryCodes na true
. Oto przykład treści żądania:
{
"resetRecoveryCodes": true
}
Resetowanie klucza współużytkowanego
Aby uzyskać nowy losowy klucz współużytkowany, skorzystaj z tego punktu końcowego, ustawiając ResetSharedKey na true
. Oto przykład treści żądania:
{
"resetSharedKey": true
}
Zresetowanie klucza powoduje automatyczne wyłączenie wymagania logowania dwuskładnikowego dla uwierzytelnionego użytkownika do momentu ponownego włączenia go przez późniejsze żądanie.
Zapomnij o maszynie
Aby usunąć flagę cookie "zapamiętaj mnie", jeśli jest obecna, wywołaj ten endpoint z wartością ForgetMachine ustawioną na true. Oto przykład treści żądania:
{
"forgetMachine": true
}
Ten punkt końcowy nie ma wpływu na uwierzytelnianie oparte na tokenach.
Użyj punktu końcowego GET /manage/info
Pobiera adres e-mail i stan potwierdzenia wiadomości e-mail zalogowanego użytkownika. Oświadczenia zostały pominięte w tym punkcie końcowym ze względów bezpieczeństwa. Jeśli są potrzebne oświadczenia, użyj interfejsów API po stronie serwera, aby skonfigurować punkt końcowy dla oświadczeń. Lub zamiast udostępniać wszystkie oświadczenia użytkowników, podaj punkt końcowy weryfikacji, który akceptuje oświadczenie i odpowiada, czy użytkownik ma je.
Żądanie nie wymaga żadnych parametrów. Treść odpowiedzi zawiera właściwości Email i IsEmailConfirmed, jak w poniższym przykładzie.
{
"email": "string",
"isEmailConfirmed": true
}
Użyj punktu końcowego POST /manage/info
Aktualizuje adres e-mail i hasło zalogowanego użytkownika. Wyślij NewEmail, NewPassword i OldPassword w treści żądania, jak pokazano w poniższym przykładzie:
{
"newEmail": "string",
"newPassword": "string",
"oldPassword": "string"
}
Oto przykład treści odpowiedzi:
{
"email": "string",
"isEmailConfirmed": false
}
Zobacz też
Aby uzyskać więcej informacji, zobacz następujące zasoby:
- wybierz rozwiązanie do zarządzania tożsamościami
- Identity rozwiązania do zarządzania dla aplikacji internetowych platformy .NET
- Prosta autoryzacja w ASP.NET Core
- Dodawanie, pobieranie i usuwanie danych użytkownika w Identity projekcie ASP.NET Core
- Tworzenie aplikacji platformy ASP.NET Core przy użyciu danych użytkowników chronionych przez autoryzację
- Potwierdzenie konta i odzyskiwanie hasła w usłudze ASP.NET Core
- Włącz generowanie kodu QR dla aplikacji uwierzytelniających TOTP w ASP.NET Core
-
Przykładowe zaplecze Web API dla SPA Plik .http pokazuje uwierzytelnianie oparte na tokenach. Na przykład:
- Nie ustawia
useCookies
- Używa nagłówka Authorization do przekazania tokenu
- Pokazuje odświeżanie w celu rozszerzenia sesji bez wymuszania ponownego logowania użytkownika
- Nie ustawia
- Przykładowa aplikacja Angular, która używa Identity do zabezpieczania backendu interfejsu API
Szablony ASP.NET Core oferują uwierzytelnianie w aplikacjach jednostronicowych (SPA) przy użyciu obsługi autoryzacji interfejsu API. ASP.NET Core Identity na potrzeby uwierzytelniania i przechowywania użytkowników jest połączony z serwerem Duende Identity do implementowania programu OpenID Connect.
Ważne
Oprogramowanie Duende może wymagać zapłacenia opłaty licencyjnej za korzystanie z serwera Duende Identity Server w środowisku produkcyjnym. Aby uzyskać więcej informacji, zobacz Migracja z platformy ASP.NET Core w wersji 5.0 do wersji 6.0.
Parametr uwierzytelniania został dodany do szablonów projektów Angular i React, podobny do parametru uwierzytelniania w szablonach projektów aplikacji internetowej (Model-View-Controller) oraz aplikacji internetowej (Razor Pages). Dozwolone wartości parametrów to None i Individual. Szablon projektu React.js i Redux nie obsługuje obecnie parametru uwierzytelniania.
Tworzenie aplikacji z obsługą autoryzacji interfejsu API
Uwierzytelnianie i autoryzacja użytkownika mogą być używane zarówno z usługami Angular, jak i React SPA. Otwórz konsolę i uruchom następujące polecenie:
Angular:
dotnet new angular -au Individual
React:
dotnet new react -au Individual
Poprzednie polecenie tworzy aplikację ASP.NET Core z katalogiem ClientApp zawierającym SPA.
Ogólny opis składników ASP.NET Core aplikacji
W poniższych sekcjach opisano dodatki do projektu, gdy jest uwzględniona obsługa uwierzytelniania:
Program.cs
Poniższe przykłady kodu bazują na pakiecie NuGet Microsoft.AspNetCore.ApiAuthorization.IdentityServer . Przykłady konfigurują uwierzytelnianie i autoryzację API przy użyciu metod rozszerzeń AddApiAuthorization i AddIdentityServerJwt. Projekty korzystające z szablonów projektów React lub Angular SPA z uwierzytelnianiem obejmują odwołanie do tego pakietu.
dotnet new angular -au Individual
generuje następujący Program.cs
plik:
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapFallbackToFile("index.html");
app.Run();
Powyższy kod konfiguruje:
Identity z domyślnym interfejsem użytkownika:
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
IdentityServer z dodatkową
AddApiAuthorization
metodą pomocnika, która konfiguruje niektóre domyślne konwencje ASP.NET Core na serwerze IdentityServer:builder.Services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Uwierzytelnianie przy użyciu dodatkowej
AddIdentityServerJwt
metody pomocniczej, która konfiguruje aplikację do weryfikowania tokenów JWT utworzonych przez usługę IdentityServer:builder.Services.AddAuthentication() .AddIdentityServerJwt();
Oprogramowanie pośredniczące do uwierzytelniania, które odpowiada za weryfikację poświadczeń żądania oraz ustawienie użytkownika w kontekście tego żądania.
app.UseAuthentication();
Oprogramowanie pośredniczące IdentityServer, które uwidacznia punkty końcowe OpenID Connect:
app.UseIdentityServer();
Ostrzeżenie
W tym artykule przedstawiono użycie parametrów połączenia. W przypadku lokalnej bazy danych użytkownik nie musi być uwierzytelniany, ale w środowisku produkcyjnym parametry połączenia czasami zawiera hasło do uwierzytelniania. Poświadczenie hasła właściciela zasobu (ROPC) jest zagrożeniem bezpieczeństwa, którego należy unikać w produkcyjnych bazach danych. Aplikacje produkcyjne powinny korzystać z najbezpieczniejszego dostępnego przepływu uwierzytelniania. Aby uzyskać więcej informacji na temat uwierzytelniania aplikacji wdrożonych w środowiskach testowych lub produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.
usługa Azure App Service na systemie Linux
W przypadku wdrożeń usługi Azure App Service na Linuxie określ wystawcę jawnie.
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "{AUTHORITY}";
});
W poprzednim kodzie symbol {AUTHORITY}
jest zastępczym miejscem dla Authority, używanym podczas wykonywania wywołań OpenID Connect.
Przykład:
options.Authority = "https://contoso-service.azurewebsites.net";
AddApiAuthorization
Ta metoda pomocnicza konfiguruje IdentityServer do korzystania z obsługiwanej przez nas konfiguracji. IdentityServer to zaawansowana i rozszerzalna struktura do obsługi problemów z zabezpieczeniami aplikacji. Jednocześnie uwidacznia niepotrzebną złożoność dla najbardziej typowych scenariuszy. W związku z tym dostępny jest zestaw konwencji i opcji konfiguracji, które są uważane za dobry punkt wyjścia. Po zmianie potrzeb uwierzytelniania pełna moc serwera IdentityServer jest nadal dostępna w celu dostosowania uwierzytelniania zgodnie z potrzebami.
AddIdentityServerJwt
Ta metoda pomocnika konfiguruje schemat zasad dla aplikacji jako domyślną procedurę obsługi uwierzytelniania. Zasady są skonfigurowane tak, aby umożliwić Identity obsługę wszystkich żądań kierowanych do dowolnej ścieżki podrzędnej Identity w obszarze adresu URL "/Identity". Usługa JwtBearerHandler
obsługuje wszystkie inne żądania. Ponadto ta metoda rejestruje zasób interfejsu <<ApplicationName>>API
API w IdentityServer z domyślnym zakresem <<ApplicationName>>API
i konfiguruje middleware tokenu bearer JWT do weryfikacji tokenów wystawionych przez IdentityServer dla aplikacji.
WeatherForecastController
W pliku zwróć uwagę [Authorize]
na atrybut zastosowany do klasy, który wskazuje, że użytkownik musi być autoryzowany na podstawie domyślnych zasad dostępu do zasobu. Domyślna polityka autoryzacji jest skonfigurowana w taki sposób, że przypadkowo używa domyślnego schematu uwierzytelniania, który AddIdentityServerJwt
ustawia jako schemat polityki wspomniany powyżej. Dzięki temu JwtBearerHandler
skonfigurowana przez taką metodę pomocnika staje się domyślną obsługą żądań do aplikacji.
ApplicationDbContext
W pliku zwróć uwagę, że to samo DbContext
jest używane w Identity, z wyjątkiem tego, że rozszerza ApiAuthorizationDbContext
(jako bardziej pochodną klasę z IdentityDbContext
), aby uwzględnić schemat dla IdentityServer.
Aby uzyskać pełną kontrolę nad schematem bazy danych, odziedzicz z jednej z dostępnych IdentityDbContext
klas i skonfiguruj kontekst, aby uwzględnić Identity schemat poprzez wywołanie metody builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value)
na OnModelCreating
.
OidcConfigurationController
Zwróć uwagę na punkt końcowy w pliku, który jest przygotowany do obsługi parametrów OIDC, których klient musi użyć.
appsettings.json
appsettings.json
W pliku głównym projektu znajduje się nowa IdentityServer
sekcja, która opisuje listę skonfigurowanych klientów. W poniższym przykładzie istnieje jeden klient. Nazwa klienta odpowiada nazwie aplikacji i jest mapowana zgodnie z konwencją do parametru OAuth ClientId
. Profil wskazuje skonfigurowany typ aplikacji. Jest ona używana wewnętrznie do napędzania konwencji, które upraszczają proces konfiguracji serwera. Istnieje kilka dostępnych profilów, jak wyjaśniono w sekcji Profile aplikacji.
"IdentityServer": {
"Clients": {
"angularindividualpreview3final": {
"Profile": "IdentityServerSPA"
}
}
}
appsettings.Development.json
W pliku głównym projektu appsettings.Development.json
znajduje się sekcja IdentityServer
opisująca klucz używany do podpisywania tokenów. Podczas wdrażania w środowisku produkcyjnym należy aprowizować i wdrażać klucz obok aplikacji, jak wyjaśniono w sekcji Wdrażanie w środowisku produkcyjnym .
"IdentityServer": {
"Key": {
"Type": "Development"
}
}
Ogólny opis aplikacji Angular
Obsługa uwierzytelniania i autoryzacji interfejsu API w szablonie usługi Angular znajduje się we własnym module Angular w katalogu ClientApp/src/api-authorization . Moduł składa się z następujących elementów:
- 3 składniki:
-
login.component.ts
: obsługuje przepływ logowania aplikacji. -
logout.component.ts
: obsługuje proces wylogowywania aplikacji. -
login-menu.component.ts
: widżet, który wyświetla jeden z następujących zestawów łączy:- Zarządzanie profilem użytkownika i link do wylogowania, gdy użytkownik jest uwierzytelniony.
- Linki do rejestracji i logowania, gdy użytkownik nie jest uwierzytelniony.
-
- Zabezpieczenie
AuthorizeGuard
trasy, które można dodać i które wymaga uwierzytelnienia użytkownika przed odwiedzeniem trasy. - Przechwytownik
AuthorizeInterceptor
HTTP, który dołącza token dostępu do wychodzących żądań HTTP kierowanych do interfejsu API, gdy użytkownik jest uwierzytelniony. - Usługa
AuthorizeService
, która obsługuje szczegóły niższego poziomu procesu uwierzytelniania i uwidacznia informacje o uwierzytelnianym użytkowniku w pozostałej części aplikacji do użycia. - Moduł Angular, który definiuje trasy skojarzone z częściami uwierzytelniania aplikacji. Udostępnia składnik menu logowania, przechwytywacz, zabezpieczenie i usługę do wykorzystania przez resztę aplikacji.
Ogólny opis aplikacji React
Obsługa uwierzytelniania i autoryzacji interfejsu API w szablonie react znajduje się w katalogu ClientApp/src/components/api-authorization . Składa się z następujących elementów:
- 4 składniki:
-
Login.js
: obsługuje przepływ logowania aplikacji. -
Logout.js
: obsługuje proces wylogowywania aplikacji. -
LoginMenu.js
: widżet, który wyświetla jeden z następujących zestawów łączy:- Zarządzanie profilem użytkownika i link do wylogowania, gdy użytkownik jest uwierzytelniony.
- Linki do rejestracji i logowania, gdy użytkownik nie jest uwierzytelniony.
-
AuthorizeRoute.js
: składnik trasy, który wymaga uwierzytelnienia użytkownika przed renderowaniem składnika wskazanego w parametrzeComponent
.
-
- Wyeksportowane
authService
wystąpienie klasyAuthorizeService
, które obsługuje szczegóły procesu uwierzytelniania niższego poziomu i uwidacznia informacje o uwierzytelnianym użytkowniku w pozostałej części aplikacji do użycia.
Po zapoznaniu się z głównymi składnikami rozwiązania możesz dokładniej przyjrzeć się poszczególnym scenariuszom aplikacji.
Wymaganie autoryzacji w nowym interfejsie API
Domyślnie system jest skonfigurowany tak, aby można było łatwo wymagać autoryzacji dla nowych interfejsów API. W tym celu utwórz nowy kontroler i dodaj [Authorize]
atrybut do klasy kontrolera lub dowolnej akcji w obrębie kontrolera.
Dostosowywanie procedury obsługi uwierzytelniania interfejsu API
Aby dostosować konfigurację programu obsługi JWT API, skonfiguruj jego wystąpienie JwtBearerOptions.
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
...
});
Procedura obsługi JWT interfejsu API zgłasza zdarzenia, które umożliwiają kontrolę nad procesem uwierzytelniania przy użyciu polecenia JwtBearerEvents
. Aby zapewnić obsługę autoryzacji interfejsu API, AddIdentityServerJwt
rejestruje własne procedury obsługi zdarzeń.
Aby dostosować obsługę zdarzenia, owiń istniejący obsługiwacz zdarzeń dodatkową logiką według potrzeb. Na przykład:
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
var onTokenValidated = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await onTokenValidated(context);
...
}
});
W poprzednim kodzie OnTokenValidated
procedura obsługi zdarzenia jest zastępowana implementacją niestandardową. Ta implementacja:
- Wywołuje oryginalną implementację zapewnianą przez obsługę autoryzacji interfejsu API.
- Uruchamianie własnej logiki niestandardowej.
Ochrona ścieżki po stronie klienta (Angular)
Ochrona trasy po stronie klienta jest wykonywana przez dodanie ochrony autoryzacji do listy zabezpieczeń do uruchomienia podczas konfigurowania trasy. Na przykład możesz zobaczyć, jak trasa fetch-data
jest skonfigurowana w głównym module aplikacji Angular.
RouterModule.forRoot([
// ...
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])
Należy pamiętać, że ochrona trasy nie chroni rzeczywistego punktu końcowego (który nadal wymaga zastosowanego [Authorize]
atrybutu), ale uniemożliwia użytkownikowi przejście do danej trasy po stronie klienta, gdy nie jest uwierzytelniony.
Uwierzytelnianie żądań interfejsu API (Angular)
Uwierzytelnianie żądań do interfejsów API hostowanych razem z aplikacją odbywa się automatycznie za pomocą przechwytnika klienta HTTP zdefiniowanego przez aplikację.
Zabezpieczenie ścieżki po stronie klienta (React)
Chroń trasę po stronie klienta przy użyciu AuthorizeRoute
składnika zamiast zwykłego Route
składnika. Zwróć na przykład uwagę na to, jak fetch-data
trasa jest skonfigurowana w składniku App
:
<AuthorizeRoute path='/fetch-data' component={FetchData} />
Ochrona trasy:
- Nie chroni rzeczywistego punktu końcowego (który nadal wymaga zastosowanego atrybutu
[Authorize]
). - Uniemożliwia użytkownikowi przejście do danej trasy po stronie klienta, tylko wtedy gdy nie jest uwierzytelniony.
Uwierzytelnianie żądań interfejsu API (React)
Uwierzytelnianie żądań w React odbywa się najpierw przez zaimportowanie wystąpienia authService
z AuthorizeService
. Token dostępu jest pobierany z authService
obiektu i jest dołączony do żądania, jak pokazano poniżej. W komponentach React ta praca jest zwykle wykonywana w componentDidMount
metodzie cyklu życia lub w wyniku interakcji z użytkownikiem.
Importowanie elementu authService
do składnika
import authService from './api-authorization/AuthorizeService'
Pobieranie i dołączanie tokenu dostępu do odpowiedzi
async populateWeatherData() {
const token = await authService.getAccessToken();
const response = await fetch('api/SampleData/WeatherForecasts', {
headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Zaimplementuj na produkcji
Aby wdrożyć aplikację w środowisku produkcyjnym, należy aprowizować następujące zasoby:
- Baza danych służąca do przechowywania kont użytkowników oraz uprawnień przyznawanych przez IdentityServer.
- Certyfikat produkcyjny do podpisywania tokenów.
- Nie ma żadnych konkretnych wymagań dotyczących tego certyfikatu; może to być certyfikat z podpisem własnym lub certyfikat aprowizowany za pośrednictwem urzędu certyfikacji.
- Można go wygenerować za pomocą standardowych narzędzi, takich jak Program PowerShell lub OpenSSL.
- Można go zainstalować w magazynie certyfikatów na maszynach docelowych lub wdrożyć jako plik pfx z silnym hasłem.
Przykład: wdrażanie u dostawcy hostingu internetowego spoza platformy Azure
W panelu hostingu internetowego utwórz lub załaduj certyfikat. Następnie w pliku aplikacji appsettings.json
zmodyfikuj IdentityServer
sekcję w celu uwzględnienia kluczowych szczegółów. Na przykład:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "WebHosting",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
W powyższym przykładzie:
-
StoreName
reprezentuje nazwę magazynu certyfikatów, w którym jest przechowywany certyfikat. W takim przypadku wskazuje on sklep hostingu internetowego. -
StoreLocation
reprezentuje miejsce ładowania certyfikatu z (CurrentUser
w tym przypadku). -
Name
odnosi się do wyróżniającego się podmiotu certyfikatu.
Przykład: Wdrażanie do usługi Azure App Service
W tej sekcji opisano wdrażanie aplikacji w usłudze aplikacja systemu Azure przy użyciu certyfikatu przechowywanego w magazynie certyfikatów. Aby zmodyfikować aplikację w celu załadowania certyfikatu z magazynu certyfikatów, wymagany jest plan usługi poziomu Standard lub lepszy przy konfigurowaniu aplikacji w portalu Azure w kolejnym kroku.
W pliku aplikacji appsettings.json
zmodyfikuj IdentityServer
sekcję, aby zawierała kluczowe szczegóły:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
- Nazwa magazynu reprezentuje nazwę magazynu certyfikatów, w którym jest przechowywany certyfikat. W takim przypadku wskazuje na osobistą przestrzeń przechowywania użytkownika.
- Lokalizacja sklepu reprezentuje miejsce załadowania certyfikatu z (
CurrentUser
lubLocalMachine
). - Właściwość nazwa certyfikatu odpowiada wyróżnionemu podmiotowi certyfikatu.
Aby wdrożyć aplikację w usłudze Azure App Service, wykonaj kroki opisane w Wdrożenie aplikacji na platformie Azure, które wyjaśniają, jak utworzyć niezbędne zasoby platformy Azure i wdrożyć aplikację w środowisku produkcyjnym.
Po wykonaniu powyższych instrukcji aplikacja zostanie wdrożona na platformie Azure, ale nie jest jeszcze funkcjonalna. Certyfikat używany przez aplikację musi być skonfigurowany w witrynie Azure Portal. Znajdź odcisk palca certyfikatu i wykonaj kroki opisane w temacie Ładowanie certyfikatów.
Chociaż te kroki obejmują protokół SSL, w witrynie Azure Portal znajduje się sekcja Certyfikaty prywatne, w której można przekazać aprowizowany certyfikat do użycia z aplikacją.
Po skonfigurowaniu aplikacji i ustawień aplikacji w witrynie Azure Portal uruchom ponownie aplikację w portalu.
Inne opcje konfiguracji
Obsługa autoryzacji interfejsu API opiera się na IdentityServer z zestawem konwencji, wartości domyślnych i ulepszeń, aby uprościć doświadczenie dla SPA. Nie trzeba dodawać, że pełna moc IdentityServer jest dostępna za kulisami, jeśli integracje z ASP.NET Core nie pokrywają twojego scenariusza. Obsługa platformy ASP.NET Core koncentruje się na aplikacjach "firmowych", w których wszystkie aplikacje są tworzone i wdrażane przez naszą organizację. W związku z tym pomoc techniczna nie jest oferowana dla takich kwestii jak zgoda lub federacja. W tych scenariuszach, użyj IdentityServer i postępuj zgodnie z ich dokumentacją.
Profile aplikacji
Profile aplikacji to wstępnie zdefiniowane konfiguracje aplikacji, które dodatkowo definiują ich parametry. Obecnie obsługiwane są następujące profile:
-
IdentityServerSPA
: reprezentuje SPA hostowany obok IdentityServer jako pojedynczą jednostkę.- Wartość domyślna
redirect_uri
to/authentication/login-callback
. - Wartość domyślna
post_logout_redirect_uri
to/authentication/logout-callback
. - Zestaw zakresów obejmuje
openid
,profile
oraz każdy zakres zdefiniowany dla interfejsów API w aplikacji. - Zestaw dozwolonych typów odpowiedzi OIDC jest
id_token token
lub każdy z nich indywidualnie (id_token
,token
). - Dozwolony tryb odpowiedzi to
fragment
.
- Wartość domyślna
-
SPA
: reprezentuje SPA, który nie jest hostowany w usłudze IdentityServer.- Zestaw zakresów obejmuje
openid
,profile
oraz każdy zakres zdefiniowany dla interfejsów API w aplikacji. - Zestaw dozwolonych typów odpowiedzi OIDC jest
id_token token
lub każdy z nich indywidualnie (id_token
,token
). - Dozwolony tryb odpowiedzi to
fragment
.
- Zestaw zakresów obejmuje
-
IdentityServerJwt
: reprezentuje interfejs API hostowany razem z usługą IdentityServer.- Aplikacja jest skonfigurowana tak, aby miała jeden zakres, który domyślnie ma nazwę aplikacji.
-
API
: reprezentuje interfejs API, który nie jest hostowany w usłudze IdentityServer.- Aplikacja jest skonfigurowana tak, aby miała jeden zakres, który domyślnie ma nazwę aplikacji.
Konfiguracja za pośrednictwem AppSettings
Skonfiguruj aplikacje za pomocą systemu konfiguracji, dodając je do listy Clients
lub Resources
.
Skonfiguruj właściwości redirect_uri
i post_logout_redirect_uri
każdego klienta, jak pokazano w poniższym przykładzie:
"IdentityServer": {
"Clients": {
"MySPA": {
"Profile": "SPA",
"RedirectUri": "https://www.example.com/authentication/login-callback",
"LogoutUri": "https://www.example.com/authentication/logout-callback"
}
}
}
Podczas konfigurowania zasobów można skonfigurować zakresy dla zasobu, jak pokazano poniżej:
"IdentityServer": {
"Resources": {
"MyExternalApi": {
"Profile": "API",
"Scopes": "a b c"
}
}
}
Konfiguracja za pomocą kodu
Można również skonfigurować klientów i zasoby za pomocą kodu przy użyciu przeciążenia AddApiAuthorization
, które podejmuje akcję w celu skonfigurowania opcji.
AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddSPA(
"My SPA", spa =>
spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
.WithLogoutRedirectUri(
"http://www.example.com/authentication/logout-callback"));
options.ApiResources.AddApiResource("MyExternalApi", resource =>
resource.WithScopes("a", "b", "c"));
});
Dodatkowe zasoby
Szablony ASP.NET Core 3.1 i nowszych oferują uwierzytelnianie w aplikacjach jednostronicowych (SPAs) przy użyciu wsparcia autoryzacji API. ASP.NET Core Identity na potrzeby uwierzytelniania i przechowywania użytkowników jest łączona z usługą IdentityServer na potrzeby implementowania programu OpenID Connect.
Parametr uwierzytelniania został dodany do szablonów projektów Angular i React, podobny do parametru uwierzytelniania w szablonach projektów aplikacji internetowej (Model-View-Controller) oraz aplikacji internetowej (Razor Pages). Dozwolone wartości parametrów to None i Individual. Szablon projektu React.js i Redux nie obsługuje obecnie parametru uwierzytelniania.
Tworzenie aplikacji z obsługą autoryzacji interfejsu API
Uwierzytelnianie i autoryzacja użytkownika mogą być używane zarówno z usługami Angular, jak i React SPA. Otwórz konsolę i uruchom następujące polecenie:
Angular:
dotnet new angular -o <output_directory_name>
React:
dotnet new react -o <output_directory_name> -au Individual
Poprzednie polecenie tworzy aplikację ASP.NET Core z katalogiem ClientApp zawierającym SPA.
Ogólny opis składników ASP.NET Core aplikacji
W poniższych sekcjach opisano dodatki do projektu, gdy jest uwzględniona obsługa uwierzytelniania:
Klasa Startup
Poniższe przykłady kodu bazują na pakiecie NuGet Microsoft.AspNetCore.ApiAuthorization.IdentityServer . Przykłady konfigurują uwierzytelnianie i autoryzację API przy użyciu metod rozszerzeń AddApiAuthorization i AddIdentityServerJwt. Projekty korzystające z szablonów projektów React lub Angular SPA z uwierzytelnianiem obejmują odwołanie do tego pakietu.
Klasa Startup
ma następujące dodatki:
Wewnątrz
Startup.ConfigureServices
metody:Identity z domyślnym interfejsem użytkownika:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<ApplicationUser>() .AddEntityFrameworkStores<ApplicationDbContext>();
IdentityServer z dodatkową
AddApiAuthorization
metodą pomocnika, która konfiguruje niektóre domyślne konwencje ASP.NET Core na serwerze IdentityServer:services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Uwierzytelnianie przy użyciu dodatkowej
AddIdentityServerJwt
metody pomocniczej, która konfiguruje aplikację do weryfikowania tokenów JWT utworzonych przez usługę IdentityServer:services.AddAuthentication() .AddIdentityServerJwt();
Wewnątrz
Startup.Configure
metody:Oprogramowanie pośredniczące do uwierzytelniania, które odpowiada za weryfikację poświadczeń żądania i przypisanie użytkownika do kontekstu żądania.
app.UseAuthentication();
Oprogramowanie pośredniczące IdentityServer, które uwidacznia punkty końcowe OpenID Connect:
app.UseIdentityServer();
Ostrzeżenie
W tym artykule przedstawiono użycie parametrów połączenia. W przypadku lokalnej bazy danych użytkownik nie musi być uwierzytelniany, ale w środowisku produkcyjnym parametry połączenia czasami zawiera hasło do uwierzytelniania. Poświadczenie hasła właściciela zasobu (ROPC) jest zagrożeniem bezpieczeństwa, którego należy unikać w produkcyjnych bazach danych. Aplikacje produkcyjne powinny korzystać z najbezpieczniejszego dostępnego przepływu uwierzytelniania. Aby uzyskać więcej informacji na temat uwierzytelniania aplikacji wdrożonych w środowiskach testowych lub produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.
usługa Azure App Service na systemie Linux
W przypadku wdrożeń Azure App Service na systemie Linux, określ wystawcę jawnie w pliku Startup.ConfigureServices
:
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "{AUTHORITY}";
});
W poprzednim kodzie symbol {AUTHORITY}
jest zastępczym miejscem dla Authority, używanym podczas wykonywania wywołań OpenID Connect.
Przykład:
options.Authority = "https://contoso-service.azurewebsites.net";
AddApiAuthorization
Ta metoda pomocnicza konfiguruje IdentityServer do korzystania z obsługiwanej przez nas konfiguracji. IdentityServer to zaawansowana i rozszerzalna struktura do obsługi problemów z zabezpieczeniami aplikacji. Jednocześnie uwidacznia niepotrzebną złożoność dla najbardziej typowych scenariuszy. W związku z tym dostępny jest zestaw konwencji i opcji konfiguracji, które są uważane za dobry punkt wyjścia. Po zmianie potrzeb uwierzytelniania pełna moc serwera IdentityServer jest nadal dostępna w celu dostosowania uwierzytelniania zgodnie z potrzebami.
AddIdentityServerJwt
Ta metoda pomocnika konfiguruje schemat zasad dla aplikacji jako domyślną procedurę obsługi uwierzytelniania. Zasady są skonfigurowane tak, aby umożliwić Identity obsługę wszystkich żądań kierowanych do dowolnej ścieżki podrzędnej Identity w obszarze adresu URL "/Identity". Usługa JwtBearerHandler
obsługuje wszystkie inne żądania. Ponadto ta metoda rejestruje zasób interfejsu <<ApplicationName>>API
API w IdentityServer z domyślnym zakresem <<ApplicationName>>API
i konfiguruje middleware tokenu bearer JWT do weryfikacji tokenów wystawionych przez IdentityServer dla aplikacji.
WeatherForecastController
W pliku zwróć uwagę [Authorize]
na atrybut zastosowany do klasy, który wskazuje, że użytkownik musi być autoryzowany na podstawie domyślnych zasad dostępu do zasobu. Domyślna polityka autoryzacji jest skonfigurowana w taki sposób, że przypadkowo używa domyślnego schematu uwierzytelniania, który AddIdentityServerJwt
ustawia jako schemat polityki wspomniany powyżej. Dzięki temu JwtBearerHandler
skonfigurowana przez taką metodę pomocnika staje się domyślną obsługą żądań do aplikacji.
ApplicationDbContext
W pliku zwróć uwagę, że to samo DbContext
jest używane w Identity, z wyjątkiem tego, że rozszerza ApiAuthorizationDbContext
(jako bardziej pochodną klasę z IdentityDbContext
), aby uwzględnić schemat dla IdentityServer.
Aby uzyskać pełną kontrolę nad schematem bazy danych, odziedzicz z jednej z dostępnych IdentityDbContext
klas i skonfiguruj kontekst, aby uwzględnić Identity schemat poprzez wywołanie metody builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value)
na OnModelCreating
.
OidcConfigurationController
Zwróć uwagę na punkt końcowy w pliku, który jest przygotowany do obsługi parametrów OIDC, których klient musi użyć.
appsettings.json
appsettings.json
W pliku głównym projektu znajduje się nowa IdentityServer
sekcja, która opisuje listę skonfigurowanych klientów. W poniższym przykładzie istnieje jeden klient. Nazwa klienta odpowiada nazwie aplikacji i jest mapowana zgodnie z konwencją do parametru OAuth ClientId
. Profil wskazuje skonfigurowany typ aplikacji. Jest ona używana wewnętrznie do napędzania konwencji, które upraszczają proces konfiguracji serwera. Istnieje kilka dostępnych profilów, jak wyjaśniono w sekcji Profile aplikacji.
"IdentityServer": {
"Clients": {
"angularindividualpreview3final": {
"Profile": "IdentityServerSPA"
}
}
}
appsettings.Development.json
W pliku głównym projektu appsettings.Development.json
znajduje się sekcja IdentityServer
opisująca klucz używany do podpisywania tokenów. Podczas wdrażania w środowisku produkcyjnym należy aprowizować i wdrażać klucz obok aplikacji, jak wyjaśniono w sekcji Wdrażanie w środowisku produkcyjnym .
"IdentityServer": {
"Key": {
"Type": "Development"
}
}
Ogólny opis aplikacji Angular
Obsługa uwierzytelniania i autoryzacji interfejsu API w szablonie usługi Angular znajduje się we własnym module Angular w katalogu ClientApp/src/api-authorization . Moduł składa się z następujących elementów:
- 3 składniki:
-
login.component.ts
: obsługuje przepływ logowania aplikacji. -
logout.component.ts
: obsługuje proces wylogowywania aplikacji. -
login-menu.component.ts
: widżet, który wyświetla jeden z następujących zestawów łączy:- Zarządzanie profilem użytkownika i link do wylogowania, gdy użytkownik jest uwierzytelniony.
- Linki do rejestracji i logowania, gdy użytkownik nie jest uwierzytelniony.
-
- Zabezpieczenie
AuthorizeGuard
trasy, które można dodać i które wymaga uwierzytelnienia użytkownika przed odwiedzeniem trasy. - Przechwytownik
AuthorizeInterceptor
HTTP, który dołącza token dostępu do wychodzących żądań HTTP przeznaczonych dla interfejsu API, gdy użytkownik jest uwierzytelniony. - Usługa
AuthorizeService
, która obsługuje szczegóły niższego poziomu procesu uwierzytelniania i uwidacznia informacje o uwierzytelnianym użytkowniku w pozostałej części aplikacji do użycia. - Moduł Angular, który definiuje trasy skojarzone z częściami uwierzytelniania aplikacji. Udostępnia składnik menu logowania, przechwytywacz, zabezpieczenie i usługę do wykorzystania przez resztę aplikacji.
Ogólny opis aplikacji React
Obsługa uwierzytelniania i autoryzacji interfejsu API w szablonie react znajduje się w katalogu ClientApp/src/components/api-authorization . Składa się z następujących elementów:
- 4 składniki:
-
Login.js
: obsługuje przepływ logowania aplikacji. -
Logout.js
: obsługuje proces wylogowywania aplikacji. -
LoginMenu.js
: widżet, który wyświetla jeden z następujących zestawów łączy:- Zarządzanie profilem użytkownika i link do wylogowania, gdy użytkownik jest uwierzytelniony.
- Linki do rejestracji i logowania, gdy użytkownik nie jest uwierzytelniony.
-
AuthorizeRoute.js
: składnik trasy, który wymaga uwierzytelnienia użytkownika przed renderowaniem składnika wskazanego w parametrzeComponent
.
-
- Wyeksportowane
authService
wystąpienie klasyAuthorizeService
, które obsługuje szczegóły procesu uwierzytelniania niższego poziomu i uwidacznia informacje o uwierzytelnionym użytkowniku dla pozostałej części aplikacji do wykorzystania.
Po zapoznaniu się z głównymi składnikami rozwiązania możesz dokładniej przyjrzeć się poszczególnym scenariuszom aplikacji.
Wymaganie autoryzacji w nowym interfejsie API
Domyślnie system jest skonfigurowany tak, aby można było łatwo wymagać autoryzacji dla nowych interfejsów API. W tym celu utwórz nowy kontroler i dodaj [Authorize]
atrybut do klasy kontrolera lub dowolnej akcji w obrębie kontrolera.
Dostosuj moduł obsługi uwierzytelniania API
Aby dostosować konfigurację programu obsługi JWT API, skonfiguruj jego wystąpienie JwtBearerOptions.
services.AddAuthentication()
.AddIdentityServerJwt();
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
...
});
Procedura obsługi JWT interfejsu API zgłasza zdarzenia, które umożliwiają kontrolę nad procesem uwierzytelniania przy użyciu polecenia JwtBearerEvents
. Aby zapewnić obsługę autoryzacji interfejsu API, AddIdentityServerJwt
rejestruje własne procedury obsługi zdarzeń.
Aby dostosować obsługę zdarzenia, owiń istniejący obsługiwacz zdarzeń dodatkową logiką według potrzeb. Na przykład:
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
var onTokenValidated = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await onTokenValidated(context);
...
}
});
W poprzednim kodzie OnTokenValidated
procedura obsługi zdarzenia jest zastępowana implementacją niestandardową. Ta implementacja:
- Wywołuje oryginalną implementację zapewnianą przez obsługę autoryzacji interfejsu API.
- Uruchom własną niestandardową logikę.
Ochrona ścieżki po stronie klienta (Angular)
Ochrona trasy po stronie klienta jest wykonywana przez dodanie ochrony autoryzacji do listy zabezpieczeń do uruchomienia podczas konfigurowania trasy. Na przykład możesz zobaczyć, jak trasa fetch-data
jest skonfigurowana w głównym module aplikacji Angular.
RouterModule.forRoot([
// ...
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])
Należy pamiętać, że ochrona trasy nie chroni rzeczywistego punktu końcowego (który nadal wymaga zastosowanego [Authorize]
atrybutu), ale uniemożliwia użytkownikowi przejście do danej trasy po stronie klienta, gdy nie jest uwierzytelniony.
Uwierzytelnianie żądań interfejsu API (Angular)
Uwierzytelnianie żądań do interfejsów API hostowanych razem z aplikacją odbywa się automatycznie za pomocą przechwytnika klienta HTTP zdefiniowanego przez aplikację.
Zabezpieczenie ścieżki po stronie klienta (React)
Chroń trasę po stronie klienta przy użyciu AuthorizeRoute
składnika zamiast zwykłego Route
składnika. Zwróć na przykład uwagę na to, jak fetch-data
trasa jest skonfigurowana w składniku App
:
<AuthorizeRoute path='/fetch-data' component={FetchData} />
Ochrona trasy:
- Nie chroni rzeczywistego punktu końcowego (który nadal wymaga zastosowanego atrybutu
[Authorize]
). - Uniemożliwia użytkownikowi przejście do danej trasy po stronie klienta, tylko wtedy gdy nie jest uwierzytelniony.
Uwierzytelnianie żądań interfejsu API (React)
Uwierzytelnianie żądań w React odbywa się najpierw przez zaimportowanie wystąpienia authService
z AuthorizeService
. Token dostępu jest pobierany z authService
obiektu i jest dołączony do żądania, jak pokazano poniżej. W komponentach React ta praca jest zwykle wykonywana w componentDidMount
metodzie cyklu życia lub w wyniku interakcji z użytkownikiem.
Importowanie elementu authService
do składnika
import authService from './api-authorization/AuthorizeService'
Pobieranie i dołączanie tokenu dostępu do odpowiedzi
async populateWeatherData() {
const token = await authService.getAccessToken();
const response = await fetch('api/SampleData/WeatherForecasts', {
headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Zaimplementuj na produkcji
Aby wdrożyć aplikację w środowisku produkcyjnym, należy aprowizować następujące zasoby:
- Baza danych służąca do przechowywania kont użytkowników oraz uprawnień przyznawanych przez IdentityServer.
- Certyfikat produkcyjny do podpisywania tokenów.
- Nie ma żadnych konkretnych wymagań dotyczących tego certyfikatu; może to być certyfikat z podpisem własnym lub certyfikat aprowizowany za pośrednictwem urzędu certyfikacji.
- Można go wygenerować za pomocą standardowych narzędzi, takich jak Program PowerShell lub OpenSSL.
- Można go zainstalować w magazynie certyfikatów na maszynach docelowych lub wdrożyć jako plik pfx z silnym hasłem.
Przykład: wdrażanie u dostawcy hostingu internetowego spoza platformy Azure
W panelu hostingu internetowego utwórz lub załaduj certyfikat. Następnie w pliku aplikacji appsettings.json
zmodyfikuj IdentityServer
sekcję w celu uwzględnienia kluczowych szczegółów. Na przykład:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "WebHosting",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
W powyższym przykładzie:
-
StoreName
reprezentuje nazwę magazynu certyfikatów, w którym jest przechowywany certyfikat. W takim przypadku wskazuje on sklep hostingu internetowego. -
StoreLocation
reprezentuje miejsce ładowania certyfikatu z (CurrentUser
w tym przypadku). -
Name
odnosi się do wyróżniającego się podmiotu certyfikatu.
Przykład: Wdrażanie do usługi Azure App Service
W tej sekcji opisano wdrażanie aplikacji w usłudze aplikacja systemu Azure przy użyciu certyfikatu przechowywanego w magazynie certyfikatów. Aby zmodyfikować aplikację w celu załadowania certyfikatu z magazynu certyfikatów, wymagany jest plan usługi poziomu Standard lub lepszy przy konfigurowaniu aplikacji w portalu Azure w kolejnym kroku.
W pliku aplikacji appsettings.json
zmodyfikuj IdentityServer
sekcję, aby zawierała kluczowe szczegóły:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
- Nazwa magazynu reprezentuje nazwę magazynu certyfikatów, w którym jest przechowywany certyfikat. W takim przypadku wskazuje na osobistą przestrzeń przechowywania użytkownika.
- Lokalizacja sklepu reprezentuje miejsce załadowania certyfikatu z (
CurrentUser
lubLocalMachine
). - Właściwość nazwa certyfikatu odpowiada wyróżnionemu podmiotowi certyfikatu.
Aby wdrożyć aplikację w usłudze Azure App Service, wykonaj kroki opisane w Wdrożenie aplikacji na platformie Azure, które wyjaśniają, jak utworzyć niezbędne zasoby platformy Azure i wdrożyć aplikację w środowisku produkcyjnym.
Po wykonaniu powyższych instrukcji aplikacja zostanie wdrożona na platformie Azure, ale nie jest jeszcze funkcjonalna. Certyfikat używany przez aplikację musi być skonfigurowany w witrynie Azure Portal. Znajdź odcisk palca certyfikatu i wykonaj kroki opisane w temacie Ładowanie certyfikatów.
Chociaż te kroki obejmują protokół SSL, w witrynie Azure Portal znajduje się sekcja Certyfikaty prywatne, w której można przekazać aprowizowany certyfikat do użycia z aplikacją.
Po skonfigurowaniu aplikacji i ustawień aplikacji w witrynie Azure Portal uruchom ponownie aplikację w portalu.
Inne opcje konfiguracji
Obsługa autoryzacji interfejsu API opiera się na maszynie wirtualnej IdentityServer z zestawem konwencji, wartości domyślnych i ulepszeń, aby uprościć środowisko dla spAs. Nie trzeba dodawać, że pełna moc IdentityServer jest dostępna za kulisami, jeśli integracje z ASP.NET Core nie pokrywają twojego scenariusza. Obsługa platformy ASP.NET Core koncentruje się na aplikacjach "firmowych", w których wszystkie aplikacje są tworzone i wdrażane przez naszą organizację. W związku z tym pomoc techniczna nie jest oferowana dla takich kwestii jak zgoda lub federacja. W tych scenariuszach, użyj IdentityServer i postępuj zgodnie z ich dokumentacją.
Profile aplikacji
Profile aplikacji to wstępnie zdefiniowane konfiguracje aplikacji, które dodatkowo definiują ich parametry. Obecnie obsługiwane są następujące profile:
-
IdentityServerSPA
: reprezentuje SPA hostowany obok IdentityServer jako pojedynczą jednostkę.- Wartość domyślna
redirect_uri
to/authentication/login-callback
. - Wartość domyślna
post_logout_redirect_uri
to/authentication/logout-callback
. - Zestaw zakresów obejmuje
openid
,profile
oraz każdy zakres zdefiniowany dla interfejsów API w aplikacji. - Zestaw dozwolonych typów odpowiedzi OIDC jest
id_token token
lub każdy z nich indywidualnie (id_token
,token
). - Dozwolony tryb odpowiedzi to
fragment
.
- Wartość domyślna
-
SPA
: reprezentuje SPA, który nie jest hostowany w usłudze IdentityServer.- Zestaw zakresów obejmuje
openid
,profile
oraz każdy zakres zdefiniowany dla interfejsów API w aplikacji. - Zestaw dozwolonych typów odpowiedzi OIDC jest
id_token token
lub każdy z nich indywidualnie (id_token
,token
). - Dozwolony tryb odpowiedzi to
fragment
.
- Zestaw zakresów obejmuje
-
IdentityServerJwt
: reprezentuje interfejs API hostowany razem z usługą IdentityServer.- Aplikacja jest skonfigurowana tak, aby miała jeden zakres, który domyślnie ma nazwę aplikacji.
-
API
: reprezentuje interfejs API, który nie jest hostowany w usłudze IdentityServer.- Aplikacja jest skonfigurowana tak, aby miała jeden zakres, który domyślnie ma nazwę aplikacji.
Konfiguracja za pośrednictwem AppSettings
Skonfiguruj aplikacje za pomocą systemu konfiguracji, dodając je do listy Clients
lub Resources
.
Skonfiguruj właściwości redirect_uri
i post_logout_redirect_uri
każdego klienta, jak pokazano w poniższym przykładzie:
"IdentityServer": {
"Clients": {
"MySPA": {
"Profile": "SPA",
"RedirectUri": "https://www.example.com/authentication/login-callback",
"LogoutUri": "https://www.example.com/authentication/logout-callback"
}
}
}
Podczas konfigurowania zasobów można skonfigurować zakresy dla zasobu, jak pokazano poniżej:
"IdentityServer": {
"Resources": {
"MyExternalApi": {
"Profile": "API",
"Scopes": "a b c"
}
}
}
Konfiguracja za pomocą kodu
Można również skonfigurować klientów i zasoby za pomocą kodu, korzystając z przeciążenia AddApiAuthorization
, które wykonuje zadanie konfiguracji opcji.
AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddSPA(
"My SPA", spa =>
spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
.WithLogoutRedirectUri(
"http://www.example.com/authentication/logout-callback"));
options.ApiResources.AddApiResource("MyExternalApi", resource =>
resource.WithScopes("a", "b", "c"));
});