Dela via


Skydda ASP.NET Core Blazor WebAssembly med ASP.NET Core Identity

Not

Det här är inte den senaste versionen av den här artikeln. Den aktuella utgåvan finns i den .NET 9-versionen av den här artikeln.

Viktig

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande versionen, se .NET 9-versionen av denna artikel.

Fristående Blazor WebAssembly appar kan skyddas med ASP.NET Core Identity genom att följa riktlinjerna i den här artikeln.

Slutpunkter för registrering, inloggning och utloggning

I stället för att använda standardgränssnittet som tillhandahålls av ASP.NET Core Identity för SPA- och Blazor-appar, som baseras på Razor Pages, anropar du MapIdentityApi i ett serverdels-API för att lägga till JSON API-slutpunkter för registrering och loggning av användare med ASP.NET Core Identity. Identity API-slutpunkter stöder även avancerade funktioner, till exempel tvåfaktorautentisering och e-postverifiering.

På klienten anropar du /register-slutpunkten för att registrera en användare med deras e-postadress och lösenord:

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

På klienten loggar du in en användare med cookie-autentisering via /login-slutpunkten och med useCookies-frågesträngen inställd på true.

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

Backend-server-API:et upprättar cookie-autentisering med ett anrop till AddIdentityCookies på autentiseringsbyggaren.

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

Tokenautentisering

För interna och mobila scenarier där vissa klienter inte stöder cookies tillhandahåller inloggnings-API:et en parameter för att begära token.

Varning

Vi rekommenderar att du använder cookies för webbläsarbaserade appar i stället för token eftersom webbläsaren hanterar cookies utan att exponera dem för JavaScript. Om du väljer att använda tokenbaserad säkerhet i webbappar ansvarar du för att säkerställa att token hålls säkra.

En anpassad token (en som är skyddad för ASP.NET Core Identity-plattformen) utfärdas som kan användas för att autentisera efterföljande begäranden. Token ska skickas i Authorization-huvudet som en bärartoken. En uppdateringstoken tillhandahålls också. Med den här token kan appen begära en ny token när den gamla upphör att gälla utan att tvinga användaren att logga in igen.

Tokenen är inte standard-JWT:er. Användningen av anpassade token är avsiktlig eftersom det inbyggda Identity-API:et främst är avsett för enkla scenarier. Tokenalternativet är inte avsett att vara en fullfjädrad identity-tjänstleverantör eller tokenserver, utan däremot ett alternativ till cookie-alternativet för klienter som inte kan använda cookies.

Följande vägledning börjar implementera tokenbaserad autentisering med inloggnings-API:et. Anpassad kod krävs för att slutföra implementeringen. För mer information, se Använd Identity för att säkra en webb-API-serverdel för SPA:er.

I stället för att server-API:et upprättar cookie-autentisering med ett anrop till AddIdentityCookies på autentiseringsverktyget, konfigurerar server-API:et bearer-token-autentisering med tilläggsmetoden AddBearerToken. Ange schemat för ägarautentiseringstoken med IdentityConstants.BearerScheme.

I Backend/Program.csändrar du autentiseringstjänsterna och konfigurationen till följande:

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

I BlazorWasmAuth/Identity/CookieAuthenticationStateProvider.cstar du bort frågesträngsparametern useCookies i metoden LoginAsync i CookieAuthenticationStateProvider:

- login?useCookies=true
+ login

Nu måste du ange anpassad kod för att parsa AccessTokenResponse på klienten och hantera åtkomst- och uppdateringstoken. För mer information, se Använd Identity för att skydda ett bakomliggande webb-API för SPA:er.

Ytterligare Identity scenarier

Scenarier som omfattas av dokumentationsuppsättningen Blazor:

Information om ytterligare Identity-scenarier som tillhandahålls av API:t finns i Använd Identity för att skydda ett webb-API-backend för SPA:er:

  • Skydda valda slutpunkter
  • Hantering av användarinformation

Använda säkra autentiseringsflöden för att underhålla känsliga data och autentiseringsuppgifter

Varning

Lagra inte apphemligheter, anslutningssträngar, autentiseringsuppgifter, lösenord, personliga identifieringsnummer (PIN),privat C#/.NET-kod eller privata nycklar/token i kod på klientsidan, vilket är alltid osäker. I test-/mellanlagrings- och produktionsmiljöer bör Blazor kod på serversidan och webb-API:er använda säkra autentiseringsflöden som undviker att underhålla autentiseringsuppgifter i projektkod eller konfigurationsfiler. Förutom testning av lokal utveckling rekommenderar vi att du undviker användning av miljövariabler för att lagra känsliga data, eftersom miljövariabler inte är den säkraste metoden. För testning av lokal utveckling rekommenderas verktyget Secret Manager för att skydda känsliga data. Mer information finns i På ett säkert sätt underhålla känsliga data och autentiseringsuppgifter.

Exempelappar

I den här artikeln fungerar exempelappar som en referens för fristående Blazor WebAssembly appar som har åtkomst till ASP.NET Core Identity via ett webb-API för serverdelen. Demonstrationen innehåller två appar:

  • Backend: En webb-API-app för serverdelen som underhåller en användare identity store för ASP.NET Core Identity.
  • BlazorWasmAuth: En fristående Blazor WebAssembly klientdelsapp med användarautentisering.

Få åtkomst till exempelapparna via den senaste versionens mapp från roten av arkivet med följande länk. Exemplen tillhandahålls för .NET 8 eller senare. Mer information om hur du kör exempelapparna finns i README-filen i mappen BlazorWebAssemblyStandaloneWithIdentity.

Visa eller ladda ned exempelkod (hur du laddar ned)

Bakgrunds-webb-API-applikationers paket och kod

Serverdelswebb-API-appen underhåller en användare identity store för ASP.NET Core Identity.

Paket

Appen använder följande NuGet-paket:

Om din app ska använda en annan EF Core databasleverantör än minnesleverantören, ska du inte skapa en paketreferens i din app för Microsoft.EntityFrameworkCore.InMemory.

I appens projektfil (.csproj) konfigureras invariant globalisering.

Exempelappkod

Appinställningar konfigurera url:er för serverdelen och klientdelen:

  • Backend app (BackendUrl): https://localhost:7211
  • BlazorWasmAuth app (FrontendUrl): https://localhost:7171

Den Backend.http filen kan användas för att testa väderdatabegäran. Observera att BlazorWasmAuth appen måste köras för att testa slutpunkten och att slutpunkten är hårdkodad i filen. Mer information finns i Använda .http-filer i Visual Studio 2022.

Följande konfiguration finns i appens Program-fil.

Användare identity med cookie-autentisering läggs till genom att anropa AddAuthentication och AddIdentityCookies. Tjänster för auktoriseringskontroller läggs till av ett anrop till AddAuthorizationBuilder.

Appen rekommenderas endast för demonstrationer och använder EF Core minnesintern databasprovider för databaskontextregistrering (AddDbContext). Databasprovidern i minnet gör det enkelt att starta om appen och testa användarflödena för registrering och inloggning. Varje körning börjar med en ny databas, men appen innehåller testanvändare som, som beskrivs senare i den här artikeln. Om databasen ändras till SQLite sparas användare mellan sessioner, men databasen måste skapas via migreringar, som du ser i självstudiekursen EF Core komma igång†. Du kan använda andra relationsprovidrar, till exempel SQL Server för din produktionskod.

Anteckning

†Introduktionshandledningen EF Core använder PowerShell-kommandon för att köra databasmigreringar vid användning av Visual Studio. En alternativ metod i Visual Studio är att använda gränssnittet för anslutna tjänster:

I Solution Explorerdubbelklickar du på Anslutna tjänster. I Service Dependencies>SQL Server Express LocalDBväljer du ellipsen (...) följt av antingen Lägg till migrering för att skapa en migrering eller Uppdatera databas för att uppdatera databasen.

Konfigurera Identity för att använda EF Core-databasen och exponera Identity endpoints via anropen till AddIdentityCore, AddEntityFrameworkStoresoch AddApiEndpoints.

En cors--princip (Cross-Origin Resource Sharing) upprättas för att tillåta begäranden från klientdels- och serverdelsappar. Återställnings-URL:er konfigureras för CORS-principen om appinställningarna inte anger dem:

  • Backend app (BackendUrl): https://localhost:5001
  • BlazorWasmAuth app (FrontendUrl): https://localhost:5002

Tjänster och slutpunkter för Swagger/OpenAPI- ingår för webb-API-dokumentation och utvecklingstestning. Mer information om NSwag finns i Komma igång med NSwag och ASP.NET Core.

Anspråk på användarroller skickas från en Minimal API-/roles slutpunkten.

Vägar mappas för Identity slutpunkter genom att anropa MapIdentityApi<AppUser>().

En utloggningsslutpunkt (/Logout) konfigureras i pipelinen för mellanprogram för att logga ut användare.

Om du vill skydda en slutpunkt lägger du till metoden RequireAuthorization-tillägg i routningsdefinitionen. För en kontroller lägger du till attributet [Authorize] till kontrollern eller åtgärden.

Mer information om grundläggande mönster för initiering och konfiguration av en DbContext-instans finns i DbContext Lifetime, Configuration och Initialization i EF Core-dokumentationen.

Fristående klientdel Blazor WebAssembly apppaket och kod

En fristående Blazor WebAssembly klientdelsapp visar användarautentisering och auktorisering för åtkomst till en privat webbsida.

Paket

Appen använder följande NuGet-paket:

Exempelappkod

Mappen Models innehåller appens modeller:

IAccountManagement-gränssnittet (Identity/CookieHandler.cs) tillhandahåller kontohanteringstjänster.

Klassen CookieAuthenticationStateProvider (Identity/CookieAuthenticationStateProvider.cs) hanterar tillståndet för cookie-baserad autentisering och tillhandahåller implementeringar av kontohanteringstjänsten som beskrivs av IAccountManagement-gränssnittet. Metoden LoginAsync möjliggör uttrycklig cookie-autentisering via frågesträngsvärdet useCookies för true. Klassen hanterar också att skapa rollanspråk för autentiserade användare.

Klassen CookieHandler (Identity/CookieHandler.cs) ser till att cookie autentiseringsuppgifter skickas med varje begäran till serverdelswebb-API:et, som hanterar Identity och underhåller Identity datalager.

wwwroot/appsettings.file innehåller serverdels- och klientdels-URL-slutpunkter.

Komponenten App exponerar autentiseringstillståndet som en sammanhängande parameter. Mer information finns i ASP.NET Core Blazor-autentisering och auktorisering.

Komponenterna MainLayout och NavMenu använder komponenten AuthorizeView för att selektivt visa innehåll baserat på användarens autentiseringsstatus.

Följande komponenter hanterar vanliga användarautentiseringsuppgifter och använder IAccountManagement tjänster:

Den PrivatePage komponenten (Components/Pages/PrivatePage.razor) kräver autentisering och visar användarens anspråk.

Tjänster och konfiguration tillhandahålls i Program -filen (Program.cs):

  • cookie-hanteraren är registrerad som en begränsad tjänst.
  • Auktoriseringstjänster är registrerade.
  • Den anpassade autentiseringstillståndsleverantören är registrerad som en omfattad tjänst.
  • Kontohanteringsgränssnittet (IAccountManagement) är registrerat.
  • Basvärd-URL:en har konfigurerats för en registrerad HTTP-klientinstans.
  • Basserverdels-URL:en har konfigurerats för en registrerad HTTP-klientinstans som används för autentiseringsinteraktioner med serverdelswebb-API:et. HTTP-klienten använder cookie-hanteraren för att säkerställa att cookie autentiseringsuppgifter skickas med varje begäran.

Anropa AuthenticationStateProvider.NotifyAuthenticationStateChanged när användarens autentiseringstillstånd ändras. Ett exempel finns i metoderna LoginAsync och LogoutAsync för klassen CookieAuthenticationStateProvider (Identity/CookieAuthenticationStateProvider.cs).

Varning

Komponenten AuthorizeView visar selektivt användargränssnittsinnehåll beroende på om användaren har behörighet. Allt innehåll i en Blazor WebAssembly app som placeras i en AuthorizeView komponent kan identifieras utan autentisering, så känsligt innehåll bör hämtas från ett serverbaserat webb-API när autentiseringen har slutförts. Mer information finns i följande resurser:

Demonstration av att sätta upp testanvändare

Klassen SeedData (SeedData.cs) visar hur du skapar testanvändare för utveckling. Testanvändaren, med namnet Leela, loggar in i appen med e-postadressen leela@contoso.com. Användarens lösenord är inställt på Passw0rd!. Leela ges Administrator och Manager roller för auktorisering, vilket gör det möjligt för användaren att komma åt chefssidan på /private-manager-page men inte redigeringssidan på /private-editor-page.

Varning

Tillåt aldrig att testanvändarkod körs i en produktionsmiljö. SeedData.InitializeAsync anropas bara i den Development miljön i Program-filen:

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

Roller

Rollanspråk skickas inte tillbaka från manage/info-slutpunkten för att skapa krav för användare av appen BlazorWasmAuth. Rollanspråk hanteras oberoende av varandra via en separat begäran i GetAuthenticationStateAsync-metoden för klassen CookieAuthenticationStateProvider (Identity/CookieAuthenticationStateProvider.cs) efter att användaren har autentiserats i Backend projektet.

I CookieAuthenticationStateProvider: görs en rollbegäran till slutpunkten /roles för API-projektet Backend-servern. Svaret läses in i en sträng genom att anropa ReadAsStringAsync(). JsonSerializer.Deserialize deserialiserar strängen till en anpassad RoleClaim matris. Slutligen läggs anspråken till i användarens anspråkssamling.

I Backend server-API:ets Program-fil hanterar ett minimalt API/roles slutpunkten. Anspråk på RoleClaimType väljs till en anonym typ och serialiseras för att återgå till BlazorWasmAuth-projektet med TypedResults.Json.

Rollslutpunkten kräver auktorisering genom att anropa RequireAuthorization. Om du bestämmer dig för att inte använda minimala API:er till förmån för kontrollanter för säkra server-API-slutpunkter måste du ange attributet [Authorize] på kontrollanter eller åtgärder.

Värdtjänster mellan domäner (konfiguration på samma plats)

exempelappar är konfigurerade för att värda de båda apparna på samma domän. Om du hostar Backend-appen på en annan domän än den BlazorWasmAuth-appen ska du avkommentera koden som konfigurerar cookie (ConfigureApplicationCookie) i Backend-appens Program-fil. Standardvärdena är:

Ändra värdena till:

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

Mer information om inställningar för samma webbplats cookie finns i följande resurser:

Skydd mot förfalskning

Endast utloggningsslutpunkten (/logout) i Backend-appen kräver uppmärksamhet för att minimera hotet från CSRF (Cross-Site Request Forgery).

Utloggningsslutpunkten kontrollerar en tom kropp för att förhindra CSRF-attacker. Genom att kräva en brödtext måste begäran göras från JavaScript, vilket är det enda sättet att komma åt autentiseringen cookie. Utloggningsslutpunkten kan inte nås av ett formulärbaserat POST. Detta förhindrar att en skadlig webbplats loggar ut användaren.

Slutpunkten skyddas dessutom av auktorisering (RequireAuthorization) för att förhindra anonym åtkomst.

Den BlazorWasmAuth klientappen behöver helt enkelt skicka ett tomt objekt {} i kroppen av begäran.

Utanför utloggningsslutpunkten krävs för skydd mot förfalskning endast när formulärdata skickas till servern som kodas som application/x-www-form-urlencoded, multipart/form-dataeller text/plain. Blazor hanterar CSRF-minskning för formulär i de flesta fall. Mer information finns i översikten över ASP.NET Core Blazor-autentisering och auktorisering och ASP.NET Core Blazor-formulär.

Begäranden till andra server-API-slutpunkter (webb-API) med application/json-kodat innehåll och CORS- aktiverat kräver inte CSRF-skydd. Därför krävs inget CSRF-skydd för Backend-appens slutpunkt för databearbetning (/data-processing). Rollerna (/roles) slutpunkt behöver inte CSRF-skydd eftersom det är en GET-slutpunkt som inte ändrar någon status.

Felsöka

Skogsavverkning

Information om hur du aktiverar felsökning eller spårningsloggning för Blazor WebAssembly autentisering finns i ASP.NET Core Blazor loggning.

Vanliga fel

Kontrollera konfigurationen för varje projekt. Kontrollera att URL:erna är korrekta:

  • Backend projekt
    • appsettings.json
      • BackendUrl
      • FrontendUrl
    • Backend.http: Backend_HostAddress
  • BlazorWasmAuth projekt: wwwroot/appsettings.json
    • BackendUrl
    • FrontendUrl

Om konfigurationen verkar vara korrekt:

  • Analysera applikationsloggar.

  • Granska nätverkstrafiken mellan BlazorWasmAuth-appen och Backend app med webbläsarens utvecklarverktyg. Ofta returneras ett exakt felmeddelande eller ett meddelande med en ledtråd till vad som orsakar problemet till klienten av serverdelsappen efter att ha gjort en begäran. Vägledning för utvecklarverktyg finns i följande artiklar:

  • Google Chrome (Google-dokumentation)

  • Microsoft Edge

  • Mozilla Firefox (Mozilla-dokumentation)

Dokumentationsteamet svarar på dokumentfeedback och buggar i artiklar. Öppna ett ärende med Öppna ett dokumentationsärende länken längst ned i artikeln. Teamet kan inte tillhandahålla produktsupport. Det finns flera offentliga supportforum som hjälper dig att felsöka en app. Vi rekommenderar följande:

Föregående forum ägs eller kontrolleras inte av Microsoft.

För icke-säkerhetsrelaterade, icke-känsliga och icke-konfidentiella, reproducerbara buggrapporter om ramverksfel, rapportera ett ärende med ASP.NET Core-produktgruppen. Öppna inte ett ärende med produktteamet förrän du noggrant har undersökt orsaken till problemet och inte kan lösa det själv eller med hjälp av communityn i ett offentligt supportforum. Produktenheten kan inte felsöka enskilda appar som har brutits på grund av enkel felkonfiguration eller användningsfall som rör tjänster från tredje part. Om en rapport är känslig eller konfidentiell eller beskriver en potentiell säkerhetsbrist i produkten som cyberattacker kan utnyttja kan du läsa Rapportering av säkerhetsproblem och buggar (dotnet/aspnetcore GitHub-lagringsplats).

Cookies och webbplatsdata

Cookies och webbplatsdata kan sparas mellan appuppdateringar och störa testning och felsökning. Rensa följande när du gör ändringar i appkoden, ändringar i användarkontot eller ändringar i appkonfigurationen:

  • Cookies för användarinloggning
  • App-cookies
  • Cachelagrade och lagrade webbplatsdata

En metod för att förhindra kvardröjande cookies och webbplatsdata från att störa testning och felsökning är att:

  • Konfigurera en webbläsare
    • Använd en webbläsare för testning som du kan konfigurera för att ta bort alla cookie och platsdata varje gång webbläsaren stängs.
    • Kontrollera att webbläsaren stängs manuellt eller av IDE för ändringar i appen, testanvändaren eller providerkonfigurationen.
  • Använd ett anpassat kommando för att öppna en webbläsare i InPrivate- eller Incognito-läge i Visual Studio:
    • Öppna dialogrutan Bläddra med i Visual Studio-knappen Kör.
    • Välj knappen Lägg till.
    • Ange sökvägen till webbläsaren i fältet Program. Följande sökvägar är typiska installationsplatser för Windows 10. Om webbläsaren är installerad på en annan plats eller om du inte använder Windows 10 anger du sökvägen till webbläsarens körbara fil.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • I fältet Argument anger du det kommandoradsalternativ som webbläsaren använder för att öppna i InPrivate- eller Inkognitoläge. Vissa webbläsare kräver appens URL.
      • Microsoft Edge: Använd -inprivate.
      • Google Chrome: Använd --incognito --new-window {URL}, där platshållaren för {URL} är url:en som ska öppnas (till exempel https://localhost:5001).
      • Mozilla Firefox: Använd -private -url {URL}, där platshållaren {URL} är url:en som ska öppnas (till exempel https://localhost:5001).
    • Ange ett namn i fältet Vänligt namn. Till exempel Firefox Auth Testing.
    • Välj knappen OK.
    • Om du vill undvika att behöva välja webbläsarprofilen för varje iteration av testning med en app anger du profilen som standard med knappen Ange som standard.
    • Kontrollera att webbläsaren är stängd av IDE för alla ändringar i appen, testanvändaren eller providerkonfigurationen.

Appuppgraderingar

En fungerande app kan misslyckas omedelbart efter att ha uppgraderat .NET Core SDK på utvecklingsdatorn eller ändrat paketversioner i appen. I vissa fall kan osammanhängande paket förstöra en app vid större uppgraderingar, De flesta av dessa problem kan åtgärdas genom att följa dessa instruktioner:

  1. Rensa det lokala systemets NuGet-paketcacheminnen genom att köra dotnet nuget locals all --clear från ett kommandogränssnitt.
  2. Ta bort projektets mappar bin och obj.
  3. Återställa och återskapa projektet.
  4. Ta bort alla filer i distributionsmappen på servern innan du distribuerar om appen.

Note

Användning av paketversioner som inte är kompatibla med appens målramverk stöds inte. Information om ett paket finns i NuGet Gallery eller FuGet Package Explorer.

Inspektera användarens anspråk

För att felsöka problem med användaranspråk kan följande UserClaims komponent användas direkt i appar eller fungera som grund för ytterligare anpassning.

UserClaims.razor:

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

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

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

<h2>Claims</h2>

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

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

    public ClaimsPrincipal? AuthenticatedUser { get; set; }

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

Ytterligare resurser