Dela via


ASP.NET Core Blazor Hybrid autentisering och auktorisering

Obs

Det här är inte den senaste versionen av den här artikeln. Se den aktuella .NET 9-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. Den aktuella utgåvan finns i .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.

Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

I den här artikeln beskrivs ASP.NET Cores stöd för konfiguration och hantering av säkerhet och ASP.NET Core Identity i Blazor Hybrid appar.

Autentisering i Blazor Hybrid appar hanteras av interna plattformsbibliotek, eftersom de ger förbättrade säkerhetsgarantier som webbläsarens sandbox-miljö inte kan erbjuda. Autentisering av interna appar använder en OS-specifik mekanism eller via ett federerat protokoll, till exempel OpenID Connect (OIDC). Följ riktlinjerna för den identity provider som du har valt för appen och integrera sedan identity ytterligare med Blazor med hjälp av vägledningen i den här artikeln.

Integrering av autentisering måste uppnå följande mål för Razor komponenter och tjänster:

  • Använd abstraktionerna i Microsoft.AspNetCore.Components.Authorization-paketet, till exempel AuthorizeView.
  • Reagera på ändringar i autentiseringskontexten.
  • Få åtkomst till autentiseringsuppgifter som tillhandahålls av appen från identity-providern, till exempel åtkomsttoken för att utföra auktoriserade API-anrop.

När autentiseringen har lagts till i en app för .NET MAUI, WPF eller Windows Forms och användarna kan logga in och logga ut korrekt kan de integrera autentisering med Blazor för att göra den autentiserade användaren tillgänglig för Razor komponenter och tjänster. Utför följande steg:

.NET MAUI appar använder klassen WebAuthenticator för att initiera webbläsarbaserade autentiseringsflöden som lyssnar efter ett återanrop till en specifik URL som registrerats med appen.

Mer information finns i följande resurser:

Windows Forms-appar använder Microsoft identity plattform för att integrera med Microsoft Entra (ME-ID) och AAD B2C. Mer information finns i Översikt över Microsoft Authentication Library (MSAL).

Skapa en anpassad AuthenticationStateProvider utan användarändringsuppdateringar

Om appen autentiserar användaren omedelbart efter att appen har lanserats och den autentiserade användaren förblir densamma under hela appens livslängd krävs inte meddelanden om användarändringar, och appen tillhandahåller endast information om den autentiserade användaren. I det här scenariot loggar användaren in i appen när appen öppnas och appen visar inloggningsskärmen igen när användaren har loggat ut. Följande ExternalAuthStateProvider är ett exempel på implementering av en anpassad AuthenticationStateProvider för det här autentiseringsscenariot.

Not

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private readonly Task<AuthenticationState> authenticationState;

    public ExternalAuthStateProvider(AuthenticatedUser user) => 
        authenticationState = Task.FromResult(new AuthenticationState(user.Principal));

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        authenticationState;
}

public class AuthenticatedUser
{
    public ClaimsPrincipal Principal { get; set; } = new();
}

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktoriseringstjänster och Blazor abstractioner till tjänstesamlingen.
  • Skapa tjänstsamlingen.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.
  • Återställ den byggda värdenheten.

I metoden MauiProgram.CreateMauiApp i MauiProgram.cslägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som returnerar en inbyggd Microsoft.Maui.Hosting.MauiApp:

- return builder.Build();

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();

var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

return host;

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktoriseringstjänster och Blazor-abstraktioner i tjänstsamlingen.
  • Skapa tjänstsamlingen och lägg till den byggda tjänstsamlingen som en resurs i appens ResourceDictionary.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.
  • Returnera den skapade värden.

I konstruktorn MainWindow(MainWindow.xaml.cs) lägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som lägger till den byggda tjänstsamlingen som en resurs i appens ResourceDictionary:

- Resources.Add("services", serviceCollection.BuildServiceProvider());

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);

var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktoriseringstjänster och abstraktioner för Blazor i tjänstsamlingen.
  • Skapa tjänstsamlingen och lägg till den byggda tjänstsamlingen till appens tjänstleverantör.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.

I konstruktorn Form1(Form1.cs) lägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som anger den byggda tjänstsamlingen till appens tjänstleverantör:

- blazorWebView1.Services = services.BuildServiceProvider();

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;

var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Skapa en anpassad AuthenticationStateProvider med uppdateringar efter användarförändringar

Om du vill uppdatera användaren medan Blazor-appen körs anropar du NotifyAuthenticationStateChanged inom AuthenticationStateProvider-implementeringen med antingen av följande metoder:

Signalera en autentiseringsuppdatering utanför BlazorWebView (alternativ 1)

En anpassad AuthenticationStateProvider kan använda en global tjänst för att signalera en autentiseringsuppdatering. Vi rekommenderar att tjänsten erbjuder en händelse som AuthenticationStateProvider kan prenumerera på, där händelsen anropar NotifyAuthenticationStateChanged.

Not

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private AuthenticationState currentUser;

    public ExternalAuthStateProvider(ExternalAuthService service)
    {
        currentUser = new AuthenticationState(service.CurrentUser);

        service.UserChanged += (newUser) =>
        {
            currentUser = new AuthenticationState(newUser);
            NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
        };
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(currentUser);
}

public class ExternalAuthService
{
    public event Action<ClaimsPrincipal>? UserChanged;
    private ClaimsPrincipal? currentUser;

    public ClaimsPrincipal CurrentUser
    {
        get { return currentUser ?? new(); }
        set
        {
            currentUser = value;

            if (UserChanged is not null)
            {
                UserChanged(currentUser);
            }
        }
    }
}

I metoden MauiProgram.CreateMauiApp i MauiProgram.cslägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();

I konstruktorn MainWindow(MainWindow.xaml.cs) lägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();

I konstruktorn Form1(Form1.cs) lägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();

Lös ExternalAuthService-tjänsten oavsett var appen autentiserar en användare:

var authService = host.Services.GetRequiredService<ExternalAuthService>();

Kör din anpassade OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider. Den autentiserade användaren (authenticatedUser i följande exempel) är en ny ClaimsPrincipal baserat på en ny ClaimsIdentity.

Ange den aktuella användaren till den autentiserade användaren:

authService.CurrentUser = authenticatedUser;

Ett alternativ till föregående metod är att ange användarens huvudnamn på System.Threading.Thread.CurrentPrincipal i stället för att ställa in det via en tjänst, vilket undviker användning av containern för beroendeinmatning:

public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(
            new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ?? 
                new ClaimsPrincipal(new ClaimsIdentity())));
}

Med den alternativa metoden läggs endast auktoriseringstjänster (AddAuthorizationCore) och CurrentThreadUserAuthenticationStateProvider (.TryAddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()) till i tjänstsamlingen.

Hantera autentisering inom BlazorWebView (alternativ 2)

En anpassad AuthenticationStateProvider kan innehålla ytterligare metoder för att utlösa inloggning och logga ut och uppdatera användaren.

Obs

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(new AuthenticationState(currentUser));

    public Task LogInAsync()
    {
        var loginTask = LogInAsyncCore();
        NotifyAuthenticationStateChanged(loginTask);

        return loginTask;

        async Task<AuthenticationState> LogInAsyncCore()
        {
            var user = await LoginWithExternalProviderAsync();
            currentUser = user;

            return new AuthenticationState(currentUser);
        }
    }

    private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
    {
        /*
            Provide OpenID/MSAL code to authenticate the user. See your identity 
            provider's documentation for details.

            Return a new ClaimsPrincipal based on a new ClaimsIdentity.
        */
        var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());

        return Task.FromResult(authenticatedUser);
    }

    public void Logout()
    {
        currentUser = new ClaimsPrincipal(new ClaimsIdentity());
        NotifyAuthenticationStateChanged(
            Task.FromResult(new AuthenticationState(currentUser)));
    }
}

I föregående exempel:

  • Anropet till LogInAsyncCore utlöser inloggningsprocessen.
  • Anropet till NotifyAuthenticationStateChanged meddelar att en uppdatering pågår, vilket gör att appen kan tillhandahålla ett tillfälligt användargränssnitt under inloggnings- eller utloggningsprocessen.
  • Returnerar loginTask uppgiften så att komponenten som utlöste inloggningen kan vänta och reagera när uppgiften har avslutats.
  • Metoden LoginWithExternalProviderAsync implementeras av utvecklaren för att logga in användaren med identity providerns SDK. Mer information finns i dokumentationen för din identity provider. Den autentiserade användaren (authenticatedUser) är en ny ClaimsPrincipal baserat på en ny ClaimsIdentity.

I MauiProgram.CreateMauiApp-metoden för MauiProgram.cslägger du till auktoriseringstjänsterna och Blazor-abstraktionen i tjänstsamlingen:

builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

I MainWindow:s konstruktor (MainWindow.xaml.cs), läggs auktoriseringstjänsterna och Blazor-abstraktionen till tjänstsamlingen:

serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

I Form1:s konstruktor (Form1.cs) lägger du till auktoriseringstjänster och Blazor-abstraktionen i tjänstsamlingen.

services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

Följande LoginComponent-komponent visar hur du loggar in en användare. I en typisk app visas LoginComponent komponenten endast i en överordnad komponent om användaren inte är inloggad i appen.

Shared/LoginComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Login">Log in</button>

@code
{
    public async Task Login()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();
    }
}

Följande LogoutComponent-komponent visar hur du loggar ut en användare. I en typisk app visas den LogoutComponent komponenten endast i en överordnad komponent om användaren är inloggad i appen.

Shared/LogoutComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Logout">Log out</button>

@code
{
    public async Task Logout()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .Logout();
    }
}

Komma åt annan autentiseringsinformation

Blazor definierar inte en abstraktion för att hantera andra autentiseringsuppgifter, till exempel åtkomsttoken som ska användas för HTTP-begäranden till webb-API:er. Vi rekommenderar att du följer identity providerns vägledning för att hantera användarens autentiseringsuppgifter med de primitiver som identity providerns SDK tillhandahåller.

Det är vanligt att identity provider-SDK:er använder ett tokenarkiv för användarautentiseringsuppgifter som lagras på enheten. Om SDK:ets tokenlagringsprimitiv läggs till i tjänstcontainern, använd SDK:ets primitiva i appen.

Det Blazor ramverket är inte medvetet om en användares autentiseringsuppgifter och interagerar inte med autentiseringsuppgifter på något sätt, så appens kod är fri att följa den metod som du anser vara mest praktisk. Följ dock de allmänna säkerhetsriktlinjerna i nästa avsnitt Andra autentiseringssäkerhetsövervägandennär du implementerar autentiseringskod i en app.

Andra säkerhetsöverväganden för autentisering

Autentiseringsprocessen är extern till Blazoroch vi rekommenderar att utvecklare får åtkomst till identity providerns vägledning för ytterligare säkerhetsvägledning.

När du implementerar autentisering:

  • Undvik autentisering i kontexten för Web View. Undvik till exempel att använda ett JavaScript OAuth-bibliotek för att utföra autentiseringsflödet. I en ensidesapp döljs inte autentiseringstoken i JavaScript och kan enkelt upptäckas av illvilliga användare och användas för skadliga ändamål. Interna appar utsätts inte för den här risken eftersom interna appar bara kan hämta token utanför webbläsarkontexten, vilket innebär att oseriösa skript från tredje part inte kan stjäla token och kompromettera appen.
  • Undvik att implementera autentiseringsarbetsflödet själv. I de flesta fall hanterar plattformsbiblioteken arbetsflödet för autentisering på ett säkert sätt med hjälp av systemets webbläsare i stället för att använda en anpassad Web View som kan kapas.
  • Undvik att använda plattformens Web View kontroll för att utföra autentisering. Förlita dig i stället på systemets webbläsare när det är möjligt.
  • Undvik att skicka token till dokumentkontexten (JavaScript). I vissa fall krävs ett JavaScript-bibliotek i dokumentet för att utföra ett auktoriserat anrop till en extern tjänst. I stället för att göra token tillgänglig för JavaScript via JS interop:
    • Ge en genererad tillfällig token till biblioteket och använd den inom Web View.
    • Avlyssna utgående nätverksförfrågan i koden.
    • Ersätt den tillfälliga token med den verkliga token och bekräfta att målet för begäran är giltigt.

Ytterligare resurser

Autentisering i Blazor Hybrid appar hanteras av interna plattformsbibliotek, eftersom de ger förbättrade säkerhetsgarantier som webbläsarens sandbox-miljö inte kan erbjuda. Autentisering av interna appar använder en OS-specifik mekanism eller via ett federerat protokoll, till exempel OpenID Connect (OIDC). Följ riktlinjerna för den identity provider som du har valt för appen och integrera sedan identity ytterligare med Blazor med hjälp av vägledningen i den här artikeln.

Integrering av autentisering måste uppnå följande mål för Razor komponenter och tjänster:

  • Använd abstraktionerna i Microsoft.AspNetCore.Components.Authorization-paketet, till exempel AuthorizeView.
  • Reagera på ändringar i autentiseringskontexten.
  • Få åtkomst till autentiseringsuppgifter som tillhandahålls av appen från identity-providern, till exempel åtkomsttoken för att utföra auktoriserade API-anrop.

När autentiseringen har lagts till i en app för .NET MAUI, WPF eller Windows Forms och användarna kan logga in och logga ut korrekt kan de integrera autentisering med Blazor för att göra den autentiserade användaren tillgänglig för Razor komponenter och tjänster. Utför följande steg:

.NET MAUI appar använder klassen WebAuthenticator för att initiera webbläsarbaserade autentiseringsflöden som lyssnar efter ett återanrop till en specifik URL som registrerats med appen.

Mer information finns i följande resurser:

Windows Forms-appar använder Microsoft identity plattform för att integrera med Microsoft Entra (ME-ID) och AAD B2C. Mer information finns i Översikt över Microsoft Authentication Library (MSAL).

Skapa en anpassad AuthenticationStateProvider utan användarändringsuppdateringar

Om appen autentiserar användaren omedelbart efter att appen har lanserats och den autentiserade användaren förblir densamma under hela appens livslängd krävs inte meddelanden om användarändringar, och appen tillhandahåller endast information om den autentiserade användaren. I det här scenariot loggar användaren in i appen när appen öppnas och appen visar inloggningsskärmen igen när användaren har loggat ut. Följande ExternalAuthStateProvider är ett exempel på implementering av en anpassad AuthenticationStateProvider för det här autentiseringsscenariot.

Anteckning

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private readonly Task<AuthenticationState> authenticationState;

    public ExternalAuthStateProvider(AuthenticatedUser user) => 
        authenticationState = Task.FromResult(new AuthenticationState(user.Principal));

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        authenticationState;
}

public class AuthenticatedUser
{
    public ClaimsPrincipal Principal { get; set; } = new();
}

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktorisationstjänster och Blazor-abstraktioner i tjänstesamlingen.
  • Skapa tjänstsamlingen.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.
  • Returnera den skapade värden.

I metoden MauiProgram.CreateMauiApp i MauiProgram.cslägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som returnerar en inbyggd Microsoft.Maui.Hosting.MauiApp:

- return builder.Build();

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();

var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

return host;

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktoriseringstjänster och Blazor-abstraktioner till tjänstsamlingen.
  • Skapa tjänstsamlingen och lägg till den byggda tjänstsamlingen som en resurs i appens ResourceDictionary.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.
  • Returnera den skapade värden.

I konstruktorn MainWindow(MainWindow.xaml.cs) lägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som lägger till den byggda tjänstsamlingen som en resurs i appens ResourceDictionary:

- Resources.Add("services", serviceCollection.BuildServiceProvider());

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);

var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Följande steg beskriver hur du:

  • Lägg till nödvändiga namnområden.
  • Lägg till auktoriseringstjänster och Blazor-abstraktioner i tjänstesamlingen.
  • Skapa tjänstsamlingen och lägg till den byggda tjänstsamlingen till appens tjänstleverantör.
  • Lös AuthenticatedUser-tjänsten för att ange den autentiserade användarens anspråksobjekt. Mer information finns i dokumentationen för din identity provider.

I konstruktorn Form1(Form1.cs) lägger du till namnområden för Microsoft.AspNetCore.Components.Authorization och System.Security.Claims:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

Ta bort följande kodrad som anger den byggda tjänstsamlingen till appens tjänstleverantör:

- blazorWebView1.Services = services.BuildServiceProvider();

Ersätt föregående kodrad med följande kod. Lägg till OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider.

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;

var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();

/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's 
documentation for details.

The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());

authenticatedUser.Principal = user;

Skapa en anpassad AuthenticationStateProvider med uppdateringar från användarens ändringar

Om du vill uppdatera användaren medan Blazor-appen körs anropar du NotifyAuthenticationStateChanged inom AuthenticationStateProvider-implementeringen med antingen av följande metoder:

Signalera en autentiseringsuppdatering utanför BlazorWebView (alternativ 1)

En anpassad AuthenticationStateProvider kan använda en global tjänst för att signalera en autentiseringsuppdatering. Vi rekommenderar att tjänsten erbjuder en händelse som AuthenticationStateProvider kan prenumerera på, där händelsen anropar NotifyAuthenticationStateChanged.

Notera

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private AuthenticationState currentUser;

    public ExternalAuthStateProvider(ExternalAuthService service)
    {
        currentUser = new AuthenticationState(service.CurrentUser);

        service.UserChanged += (newUser) =>
        {
            currentUser = new AuthenticationState(newUser);
            NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
        };
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(currentUser);
}

public class ExternalAuthService
{
    public event Action<ClaimsPrincipal>? UserChanged;
    private ClaimsPrincipal? currentUser;

    public ClaimsPrincipal CurrentUser
    {
        get { return currentUser ?? new(); }
        set
        {
            currentUser = value;

            if (UserChanged is not null)
            {
                UserChanged(currentUser);
            }
        }
    }
}

I metoden MauiProgram.CreateMauiApp i MauiProgram.cslägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();

I konstruktorn MainWindow(MainWindow.xaml.cs) lägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();

I konstruktorn Form1(Form1.cs) lägger du till ett namnområde för Microsoft.AspNetCore.Components.Authorization:

using Microsoft.AspNetCore.Components.Authorization;

Lägg till auktoriseringstjänster och Blazor abstraktioner i tjänstsamlingen:

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();

Lös ExternalAuthService-tjänsten oavsett var appen autentiserar en användare:

var authService = host.Services.GetRequiredService<ExternalAuthService>();

Kör din anpassade OpenID/MSAL-kod för att autentisera användaren. Mer information finns i dokumentationen för din identity provider. Den autentiserade användaren (authenticatedUser i följande exempel) är en ny ClaimsPrincipal baserat på en ny ClaimsIdentity.

Ange den aktuella användaren till den autentiserade användaren:

authService.CurrentUser = authenticatedUser;

Ett alternativ till föregående metod är att ange användarens huvudnamn på System.Threading.Thread.CurrentPrincipal i stället för att ställa in det via en tjänst, vilket undviker användning av containern för beroendeinmatning:

public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(
            new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ?? 
                new ClaimsPrincipal(new ClaimsIdentity())));
}

Med den alternativa metoden läggs endast auktoriseringstjänster (AddAuthorizationCore) och CurrentThreadUserAuthenticationStateProvider (.AddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()) till i tjänstsamlingen.

Hantera autentisering inom BlazorWebView (alternativ 2)

En anpassad AuthenticationStateProvider kan innehålla ytterligare metoder för att utlösa inloggning och logga ut och uppdatera användaren.

Not

Följande anpassade AuthenticationStateProvider deklarerar inte ett namnområde för att göra kodexemplet tillämpligt för någon Blazor Hybrid app. Bästa praxis är dock att ange appens namnområde när du implementerar exemplet i en produktionsapp.

ExternalAuthStateProvider.cs:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;

public class ExternalAuthStateProvider : AuthenticationStateProvider
{
    private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(new AuthenticationState(currentUser));

    public Task LogInAsync()
    {
        var loginTask = LogInAsyncCore();
        NotifyAuthenticationStateChanged(loginTask);

        return loginTask;

        async Task<AuthenticationState> LogInAsyncCore()
        {
            var user = await LoginWithExternalProviderAsync();
            currentUser = user;

            return new AuthenticationState(currentUser);
        }
    }

    private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
    {
        /*
            Provide OpenID/MSAL code to authenticate the user. See your identity 
            provider's documentation for details.

            Return a new ClaimsPrincipal based on a new ClaimsIdentity.
        */
        var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());

        return Task.FromResult(authenticatedUser);
    }

    public void Logout()
    {
        currentUser = new ClaimsPrincipal(new ClaimsIdentity());
        NotifyAuthenticationStateChanged(
            Task.FromResult(new AuthenticationState(currentUser)));
    }
}

I föregående exempel:

  • Anropet till LogInAsyncCore utlöser inloggningsprocessen.
  • Anropet till NotifyAuthenticationStateChanged meddelar att en uppdatering pågår, vilket gör att appen kan tillhandahålla ett tillfälligt användargränssnitt under inloggnings- eller utloggningsprocessen.
  • Returnerar loginTask returnerar uppgiften så att komponenten som utlöste inloggningen kan vänta och reagera när aktiviteten har slutförts.
  • Metoden LoginWithExternalProviderAsync implementeras av utvecklaren för att logga in användaren med identity providerns SDK. Mer information finns i dokumentationen för din identity provider. Den autentiserade användaren (authenticatedUser) är en ny ClaimsPrincipal baserat på en ny ClaimsIdentity.

I MauiProgram.CreateMauiApp-metoden för MauiProgram.cs, lägg till auktoriseringstjänster och Blazor-abstraktion i tjänstsamlingen.

builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

I MainWindow:s konstruktor (MainWindow.xaml.cs) lägger du till auktoriseringstjänsterna och Blazor-abstraktionen i tjänstsamlingen.

serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

I Form1:s konstruktor (Form1.cs) lägger du till auktoriseringstjänsterna och Blazor-abstraktionen i tjänstsamlingen:

services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

Följande LoginComponent-komponent visar hur du loggar in en användare. I en typisk app visas LoginComponent komponenten endast i en överordnad komponent om användaren inte är inloggad i appen.

Shared/LoginComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Login">Log in</button>

@code
{
    public async Task Login()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();
    }
}

Följande LogoutComponent-komponent visar hur du loggar ut en användare. I en typisk app visas den LogoutComponent komponenten endast i en överordnad komponent om användaren är inloggad i appen.

Shared/LogoutComponent.razor:

@inject AuthenticationStateProvider AuthenticationStateProvider

<button @onclick="Logout">Log out</button>

@code
{
    public async Task Logout()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .Logout();
    }
}

Komma åt annan autentiseringsinformation

Blazor definierar inte en abstraktion för att hantera andra autentiseringsuppgifter, till exempel åtkomsttoken som ska användas för HTTP-begäranden till webb-API:er. Vi rekommenderar att du följer identity providerns vägledning för att hantera användarens autentiseringsuppgifter med de primitiver som identity providerns SDK tillhandahåller.

Det är vanligt att identity provider-SDK:er använder ett tokenarkiv för användarautentiseringsuppgifter som lagras på enheten. Om SDK:ets tokenlagringsmekanism läggs till i tjänstcontainern, använd SDK:ets grundläggande funktionsobjekt inom appen.

Det Blazor ramverket är inte medvetet om en användares autentiseringsuppgifter och interagerar inte med autentiseringsuppgifter på något sätt, så appens kod är fri att följa den metod som du anser vara mest praktisk. Följ dock de allmänna säkerhetsriktlinjerna i nästa avsnitt Andra autentiseringssäkerhetsövervägandennär du implementerar autentiseringskod i en app.

Andra säkerhetsöverväganden för autentisering

Autentiseringsprocessen är extern till Blazoroch vi rekommenderar att utvecklare får åtkomst till identity providerns vägledning för ytterligare säkerhetsvägledning.

När du implementerar autentisering:

  • Undvik autentisering i kontexten för Web View. Undvik till exempel att använda ett JavaScript OAuth-bibliotek för att utföra autentiseringsflödet. I en enkeltsidorapplikation döljs inte autentiseringstoken i JavaScript och kan lätt upptäckas av illvilliga användare och användas för skadliga syften. Interna appar utsätts inte för den här risken eftersom interna appar bara kan hämta token utanför webbläsarkontexten, vilket innebär att oseriösa skript från tredje part inte kan stjäla token och kompromettera appen.
  • Undvik att implementera autentiseringsarbetsflödet själv. I de flesta fall hanterar plattformsbiblioteken arbetsflödet för autentisering på ett säkert sätt med hjälp av systemets webbläsare i stället för att använda en anpassad Web View som kan kapas.
  • Undvik att använda plattformens Web View kontroll för att utföra autentisering. Förlita dig i stället på systemets webbläsare när det är möjligt.
  • Undvik att skicka token till dokumentkontexten (JavaScript). I vissa fall krävs ett JavaScript-bibliotek i dokumentet för att utföra ett auktoriserat anrop till en extern tjänst. I stället för att göra token tillgänglig för JavaScript via JS interop:
    • Ange en genererad tillfällig token till biblioteket och inom Web View.
    • Fånga upp utgående nätverksbegäran i kod.
    • Ersätt den tillfälliga token med den verkliga token och bekräfta att målet för begäran är giltigt.

Ytterligare resurser