Dela via


ASP.NET Core Blazor WebAssembly ytterligare säkerhetsscenarier

Note

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Warning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Important

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 utgåvan, se .NET 9-versionen av den här artikeln .

I den här artikeln beskrivs ytterligare säkerhetsscenarier för Blazor WebAssembly appar.

Bifoga token till utgående begäranden

AuthorizationMessageHandler är en DelegatingHandler som används för att bearbeta åtkomsttokens. Token hämtas med hjälp av IAccessTokenProvider tjänsten, som registreras av ramverket. Om en token inte kan hämtas genereras en AccessTokenNotAvailableException . AccessTokenNotAvailableException har en Redirect metod som navigerar till AccessTokenResult.InteractiveRequestUrl med hjälp av angiven AccessTokenResult.InteractionOptions för att tillåta uppdatering av åtkomsttoken.

För enkelhetens skull tillhandahåller ramverket den BaseAddressAuthorizationMessageHandler förkonfigurerade med appens basadress som en auktoriserad URL. Åtkomsttoken läggs bara till när begärande-URI:n finns i appens bas-URI. När URI:er för utgående begäran inte finns i appens bas-URI använder du en anpassad AuthorizationMessageHandler klass (rekommenderas) eller konfigurerar AuthorizationMessageHandler.

Note

Förutom klientappkonfigurationen för server-API-åtkomst måste server-API:et även tillåta cors-begäranden (cross-origin requests) när klienten och servern inte finns på samma basadress. Mer information om CORS-konfiguration på serversidan finns i cors-avsnittet (Cross-Origin Resource Sharing) senare i den här artikeln.

I följande exempel:

I följande exempel HttpClientFactoryServiceCollectionExtensions.AddHttpClient är ett tillägg i Microsoft.Extensions.Http. Lägg till paketet i en app som inte redan refererar till det.

Note

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

...

builder.Services.AddHttpClient("WebAPI", 
        client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("WebAPI"));

För en värdbaserad Blazor som baseras på finns begärande-URIBlazor WebAssembly:er i appens bas-URI. Därför tilldelas IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)) till HttpClient.BaseAddress i en app som genereras från en projektmall.

Den konfigurerade HttpClient används för att göra auktoriserade begäranden med hjälp av try-catch mönstret:

@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject HttpClient Http

...

protected override async Task OnInitializedAsync()
{
    try
    {
        var examples = 
            await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");

        ...
    }
    catch (AccessTokenNotAvailableException exception)
    {
        exception.Redirect();
    }
}

Scenarier för anpassad autentiseringsbegäran

Följande scenarier visar hur du anpassar autentiseringsbegäranden och hur du hämtar inloggningssökvägen från autentiseringsalternativ.

Anpassa inloggningsprocessen

Hantera ytterligare parametrar till en inloggningsbegäran med följande metoder en eller flera gånger på en ny instans av InteractiveRequestOptions:

I följande LoginDisplay komponentexempel läggs ytterligare parametrar till i inloggningsbegäran:

  • prompt är inställt loginpå : Tvingar användaren att ange sina autentiseringsuppgifter för den begäran och negera enkel inloggning.
  • loginHint är inställt på peter@contoso.com: I förväg fylls fältet användarnamn/e-postadress på inloggningssidan för användaren till peter@contoso.com. Appar använder ofta den här parametern under återautentisering, efter att redan har extraherat användarnamnet från en tidigare inloggning med hjälp av anspråket preferred_username.

Shared/LoginDisplay.razor:

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity?.Name!
        <button @onclick="BeginLogOut">Log out</button>
    </Authorized>
    <NotAuthorized>
        <button @onclick="BeginLogIn">Log in</button>
    </NotAuthorized>
</AuthorizeView>

@code{
    public void BeginLogOut()
    {
        Navigation.NavigateToLogout("authentication/logout");
    }

    public void BeginLogIn()
    {
        InteractiveRequestOptions requestOptions =
            new()
            {
                Interaction = InteractionType.SignIn,
                ReturnUrl = Navigation.Uri,
            };

        requestOptions.TryAddAdditionalParameter("prompt", "login");
        requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");

        Navigation.NavigateToLogin("authentication/login", requestOptions);
    }
}

Mer information finns i följande resurser:

Anpassa alternativ innan du hämtar en token interaktivt

Om en AccessTokenNotAvailableException inträffar kan du hantera ytterligare parametrar för en ny begäran om åtkomsttoken för identitetsprovidern med följande metoder en eller flera gånger på en ny instans av InteractiveRequestOptions:

I följande exempel som hämtar JSON-data via webb-API läggs ytterligare parametrar till i omdirigeringsbegäran om en åtkomsttoken inte är tillgänglig (AccessTokenNotAvailableException genereras):

  • prompt är inställt loginpå : Tvingar användaren att ange sina autentiseringsuppgifter för den begäran och negera enkel inloggning.
  • loginHint är inställt på peter@contoso.com: I förväg fylls fältet användarnamn/e-postadress på inloggningssidan för användaren till peter@contoso.com. Appar använder ofta den här parametern under återautentisering, efter att redan har extraherat användarnamnet från en tidigare inloggning med hjälp av anspråket preferred_username.
try
{
    var examples = await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");

    ...
}
catch (AccessTokenNotAvailableException ex)
{
    ex.Redirect(requestOptions => {
        requestOptions.TryAddAdditionalParameter("prompt", "login");
        requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");
    });
}

I föregående exempel förutsätter vi att:

Mer information finns i följande resurser:

Anpassa alternativ när du använder en IAccessTokenProvider

Om det inte går att hämta en token när du använder en IAccessTokenProviderhanterar du ytterligare parametrar för en ny begäran om åtkomsttoken för identitetsprovidern med följande metoder en eller flera gånger på en ny instans av InteractiveRequestOptions:

I följande exempel som försöker hämta en åtkomsttoken för användaren läggs ytterligare parametrar till i inloggningsbegäran om försöket att hämta en token misslyckas när TryGetToken anropas:

  • prompt är inställt loginpå : Tvingar användaren att ange sina autentiseringsuppgifter för den begäran och negera enkel inloggning.
  • loginHint är inställt på peter@contoso.com: I förväg fylls fältet användarnamn/e-postadress på inloggningssidan för användaren till peter@contoso.com. Appar använder ofta den här parametern under återautentisering, efter att redan har extraherat användarnamnet från en tidigare inloggning med hjälp av anspråket preferred_username.
var tokenResult = await TokenProvider.RequestAccessToken(
    new AccessTokenRequestOptions
    {
        Scopes = [ ... ]
    });

if (!tokenResult.TryGetToken(out var token))
{
    tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
    tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint", 
        "peter@contoso.com");

    Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl, 
        accessTokenResult.InteractionOptions);
}
var tokenResult = await TokenProvider.RequestAccessToken(
    new AccessTokenRequestOptions
    {
        Scopes = new[] { ... }
    });

if (!tokenResult.TryGetToken(out var token))
{
    tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
    tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint", 
        "peter@contoso.com");

    Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl, 
        accessTokenResult.InteractionOptions);
}

Föregående exempel förutsätter:

Mer information finns i följande resurser:

Logga ut med en anpassad retur-URL

I följande exempel loggas användaren ut och användaren returneras till /goodbye slutpunkten:

Navigation.NavigateToLogout("authentication/logout", "goodbye");

Hämta inloggningssökvägen från autentiseringsalternativen

Hämta den konfigurerade inloggningssökvägen från RemoteAuthenticationOptions:

var loginPath = 
    RemoteAuthOptions.Get(Options.DefaultName).AuthenticationPaths.LogInPath;

Föregående exempel förutsätter:

Anpassad AuthorizationMessageHandler klass

Den här vägledningen i det här avsnittet rekommenderas för klientappar som gör utgående begäranden till URI:er som inte finns i appens bas-URI.

I följande exempel utökar en anpassad klass AuthorizationMessageHandler för användning som DelegatingHandler för en HttpClient. ConfigureHandler konfigurerar den här hanteraren för att auktorisera utgående HTTP-begäranden med hjälp av en åtkomsttoken. Åtkomsttoken kopplas endast om minst en av de auktoriserade URL:erna är en bas för begärande-URI :n (HttpRequestMessage.RequestUri).

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
    public CustomAuthorizationMessageHandler(IAccessTokenProvider provider, 
        NavigationManager navigation)
        : base(provider, navigation)
    {
        ConfigureHandler(
            authorizedUrls: [ "https://api.contoso.com/v1.0" ],
            scopes: [ "example.read", "example.write" ]);
    }
}

Note

I det här avsnittet används föregående meddelandehanterare när en konfigurerad HttpClient skapas från en inmatad IHttpClientFactory. Om du inte använder en IHttpClientFactory, måste du skapa en HttpClientHandler-instans och tilldela den till AuthorizationMessageHandler: DelegatingHandler.InnerHandler

InnerHandler = new HttpClientHandler();

Du behöver inte göra den tidigare InnerHandler-tilldelningen om du använder IHttpClientFactory, som anropet ExampleAPIMethod i detta avsnitt visar senare.

I föregående kod är omfången example.read och example.write generiska exempel som inte är avsedda att återspegla giltiga omfång för någon viss provider.

I filen Program registreras CustomAuthorizationMessageHandler som en tillfällig tjänst och konfigureras som DelegatingHandler för utgående HttpResponseMessage instanser som görs av en namngiven HttpClient.

I följande exempel HttpClientFactoryServiceCollectionExtensions.AddHttpClient är ett tillägg i Microsoft.Extensions.Http. Lägg till paketet i en app som inte redan refererar till det.

Note

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

builder.Services.AddTransient<CustomAuthorizationMessageHandler>();

builder.Services.AddHttpClient("WebAPI",
        client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
    .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();

Note

I föregående exempel CustomAuthorizationMessageHandlerDelegatingHandler registreras som en tillfällig tjänst för AddHttpMessageHandler. Tillfällig registrering rekommenderas för IHttpClientFactory, som hanterar sina egna DI-omfång. Mer information finns i följande resurser:

För en värdbaserad Blazor lösning baserad på Blazor WebAssembly tilldelas till IWebAssemblyHostEnvironment.BaseAddress.

Den konfigurerade HttpClient används för att göra auktoriserade begäranden med hjälp av try-catch mönstret. Där klienten skapas med CreateClient (Microsoft.Extensions.Http -paketet) anges de HttpClient instanser som innehåller åtkomsttoken när begäranden görs till server-API:et. Om begärande-URI:n är en relativ URI, som den är i följande exempel (ExampleAPIMethod), kombineras den med BaseAddress när klientappen gör begäran:

@inject IHttpClientFactory ClientFactory

...

@code {
    protected override async Task OnInitializedAsync()
    {
        try
        {
            var client = ClientFactory.CreateClient("WebAPI");

            var examples = 
                await client.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");

            ...
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

Konfigurera AuthorizationMessageHandler

AuthorizationMessageHandler kan konfigureras med auktoriserade URL:er, omfång och en retur-URL med hjälp av ConfigureHandler metoden. ConfigureHandler konfigurerar hanteraren för att auktorisera utgående HTTP-begäranden med hjälp av en åtkomsttoken. Åtkomsttoken kopplas endast om minst en av de auktoriserade URL:erna är en bas för begärande-URI :n (HttpRequestMessage.RequestUri). Om den begärda URI:n är en relativ URI kombineras den med BaseAddress.

I följande exempel AuthorizationMessageHandler konfigurerar en HttpClient i Program filen:

using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

...

builder.Services.AddScoped(sp => new HttpClient(
    sp.GetRequiredService<AuthorizationMessageHandler>()
    .ConfigureHandler(
        authorizedUrls: [ "https://api.contoso.com/v1.0" ],
        scopes: [ "example.read", "example.write" ])
    .InnerHandler = new HttpClientHandler())
{
    BaseAddress = new Uri("https://api.contoso.com/v1.0")
});

I koden ovan:

För en värdbaserad Blazor lösning, baserad på Blazor WebAssembly projektmallen, tilldelas IWebAssemblyHostEnvironment.BaseAddress följande:

  • Den HttpClient.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)).
  • En URL för matrisen authorizedUrls .

Skrivet HttpClient

En typbeskriven klient kan definieras som hanterar alla http- och tokenförvärvsproblem inom en enda klass.

WeatherForecastClient.cs:

using System.Net.Http.Json;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using static {PACKAGE ID/ASSEMBLY NAME}.Data;

public class WeatherForecastClient(HttpClient http)
{
    private WeatherForecast[]? forecasts;

    public async Task<WeatherForecast[]> GetForecastAsync()
    {
        try
        {
            forecasts = await http.GetFromJsonAsync<WeatherForecast[]>(
                "WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }

        return forecasts ?? Array.Empty<WeatherForecast>();
    }
}

I föregående exempel WeatherForecast är typen en statisk klass som innehåller väderprognosdata. Platshållaren {PACKAGE ID/ASSEMBLY NAME} är projektets paket-ID (<PackageId> i projektfilen) för ett bibliotek eller sammansättningsnamn för en app (till exempel using static BlazorSample.Data;).

I följande exempel HttpClientFactoryServiceCollectionExtensions.AddHttpClient är ett tillägg i Microsoft.Extensions.Http. Lägg till paketet i en app som inte redan refererar till det.

Note

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

I filen Program:

using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

...

builder.Services.AddHttpClient<WeatherForecastClient>(
        client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

För en värdbaserad Blazor lösning baserad på Blazor WebAssembly tilldelas till IWebAssemblyHostEnvironment.BaseAddress.

I en komponent som hämtar väderdata:

@inject WeatherForecastClient Client

...

protected override async Task OnInitializedAsync()
{
    forecasts = await Client.GetForecastAsync();
}

HttpClient Konfigurera hanteraren

Hanteraren kan konfigureras ytterligare med ConfigureHandler för utgående HTTP-begäranden.

I följande exempel HttpClientFactoryServiceCollectionExtensions.AddHttpClient är ett tillägg i Microsoft.Extensions.Http. Lägg till paketet i en app som inte redan refererar till det.

Note

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

I filen Program:

builder.Services.AddHttpClient<WeatherForecastClient>(
        client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
    .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
    .ConfigureHandler(
        authorizedUrls: [ "https://api.contoso.com/v1.0" ],
        scopes: [ "example.read", "example.write" ]));
builder.Services.AddHttpClient<WeatherForecastClient>(
        client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
    .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
    .ConfigureHandler(
        authorizedUrls: new[] { "https://api.contoso.com/v1.0" },
        scopes: new[] { "example.read", "example.write" }));

I föregående kod är omfången example.read och example.write generiska exempel som inte är avsedda att återspegla giltiga omfång för någon viss provider.

För en värdbaserad Blazor lösning, baserad på Blazor WebAssembly projektmallen, tilldelas IWebAssemblyHostEnvironment.BaseAddress följande:

  • Den HttpClient.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)).
  • En URL för matrisen authorizedUrls .

Oautentiserade eller obehöriga webb-API-begäranden i en app med en säker standardklient

En app som vanligtvis använder en säker standard HttpClient kan också göra oautentiserade eller obehöriga webb-API-begäranden genom att konfigurera en namngiven HttpClient.

I följande exempel HttpClientFactoryServiceCollectionExtensions.AddHttpClient är ett tillägg i Microsoft.Extensions.Http. Lägg till paketet i en app som inte redan refererar till det.

Note

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

I filen Program:

builder.Services.AddHttpClient("WebAPI.NoAuthenticationClient", 
    client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"));

För en värdbaserad Blazor lösning baserad på Blazor WebAssembly tilldelas till IWebAssemblyHostEnvironment.BaseAddress.

Den föregående registreringen är ett tillägg till den befintliga säkra standardregistreringen HttpClient.

En komponent skapar HttpClient från IHttpClientFactory (Microsoft.Extensions.Http -paketet) för att göra oautentiserade eller obehöriga begäranden:

@inject IHttpClientFactory ClientFactory

...

@code {
    protected override async Task OnInitializedAsync()
    {
        var client = ClientFactory.CreateClient("WebAPI.NoAuthenticationClient");

        var examples = await client.GetFromJsonAsync<ExampleType[]>(
            "ExampleNoAuthentication");

        ...
    }
}

Note

Kontrollanten i server-APIExampleNoAuthenticationController:et är i föregående exempel inte markerad med attributet[Authorize] .

Beslutet om att använda en säker klient eller en osäker klient som standardinstans HttpClient är upp till utvecklaren. Ett sätt att fatta det här beslutet är att överväga antalet autentiserade och oautentiserade slutpunkter som appen kontaktar. Om de flesta av appens begäranden är att skydda API-slutpunkter använder du den autentiserade HttpClient instansen som standard. Annars registrerar du den oautentiserade HttpClient instansen som standard.

En alternativ metod för att använda IHttpClientFactory är att skapa en skrivskyddad klient för oautentiserad åtkomst till anonyma slutpunkter.

Begära ytterligare åtkomsttoken

Åtkomsttoken kan hämtas manuellt genom att anropa IAccessTokenProvider.RequestAccessToken. I följande exempel krävs ett ytterligare omfång av en app för standardvärdet HttpClient. Exemplet Microsoft Authentication Library (MSAL) konfigurerar omfånget med MsalProviderOptions:

I filen Program:

builder.Services.AddMsalAuthentication(options =>
{
    ...

    options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 1}");
    options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 2}");
}

Platshållarna {CUSTOM SCOPE 1} och {CUSTOM SCOPE 2} i föregående exempel är anpassade områden.

Note

AdditionalScopesToConsent kan inte etablera delegerade användarbehörigheter för Microsoft Graph via användargränssnittet för Microsoft Entra-ID-medgivande när en användare först använder en app som är registrerad i Microsoft Azure. Mer information finns i Använda Graph API med ASP.NET Core Blazor WebAssembly.

Metoden IAccessTokenProvider.RequestAccessToken erbjuder en överlagring som gör att en app kan tillhandahålla en åtkomsttoken med en viss uppsättning behörigheter.

I en Razor komponent:

@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider

...

var tokenResult = await TokenProvider.RequestAccessToken(
    new AccessTokenRequestOptions
    {
        Scopes = [ "{CUSTOM SCOPE 1}", "{CUSTOM SCOPE 2}" ]
    });

if (tokenResult.TryGetToken(out var token))
{
    ...
}
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider

...

var tokenResult = await TokenProvider.RequestAccessToken(
    new AccessTokenRequestOptions
    {
        Scopes = new[] { "{CUSTOM SCOPE 1}", "{CUSTOM SCOPE 2}" }
    });

if (tokenResult.TryGetToken(out var token))
{
    ...
}

Platshållarna {CUSTOM SCOPE 1} och {CUSTOM SCOPE 2} i föregående exempel är anpassade områden.

AccessTokenResult.TryGetToken returnerar:

  • true för användning med token.
  • false om token inte hämtas.

Resursdelning mellan ursprungsdomäner (CORS)

När du skickar autentiseringsuppgifter (auktoriseringscookies/huvuden) på CORS-begäranden Authorization måste huvudet tillåtas av CORS-principen.

Följande princip innehåller konfiguration för:

  • Ursprung för begäran (http://localhost:5000, https://localhost:5001).
  • Använd valfri metod.
  • Content-Type och Authorization rubriker. Om du vill tillåta ett anpassat huvud (till exempel x-custom-header), listar du rubriken när du anropar WithHeaders.
  • Autentiseringsuppgifter som anges av JavaScript-kod på klientsidan (credentials egenskapen är inställd på include).
app.UseCors(policy => 
    policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
        .AllowAnyMethod()
        .WithHeaders(HeaderNames.ContentType, HeaderNames.Authorization, 
            "x-custom-header")
        .AllowCredentials());

En värdbaserad Blazor lösning som baseras på Blazor WebAssembly projektmallen använder samma basadress för klient- och serverapparna. Klientappens HttpClient.BaseAddress är inställd på en URI builder.HostEnvironment.BaseAddressför . CORS-konfiguration krävs inte i standardkonfigurationen för en värdbaserad Blazor lösning. Ytterligare klientappar som inte hanteras av serverprojektet och inte delar serverappens basadress kräver CORS-konfiguration i serverprojektet.

Mer information finns i Aktivera CORS (Cross-Origin Requests) i ASP.NET Core och exempelappens HTTP Request Tester-komponent (Components/HTTPRequestTester.razor).

Hantera tokenbegärandefel

När ett ensidesprogram (SPA) autentiserar en användare med OpenID Connect (OIDC) underhålls autentiseringstillståndet lokalt inom SPA och i providern Identity (IP) i form av en session cookie som har angetts som ett resultat av att användaren anger sina autentiseringsuppgifter.

De token som IP-adressen genererar för användaren är vanligtvis giltiga under korta tidsperioder, ungefär en timme normalt, så klientappen måste regelbundet hämta nya token. Annars loggas användaren ut när de beviljade token upphör att gälla. I de flesta fall kan OIDC-klienter etablera nya token utan att användaren behöver autentisera igen tack vare autentiseringstillståndet eller "sessionen" som hålls inom IP-adressen.

Det finns vissa fall där klienten inte kan hämta en token utan användarinteraktion, till exempel när användaren av någon anledning uttryckligen loggar ut från IP-adressen. Det här scenariot inträffar om en användare besöker https://login.microsoftonline.com och loggar ut. I dessa scenarier vet appen inte direkt att användaren har loggat ut. Alla token som klienten innehåller kanske inte längre är giltiga. Klienten kan inte heller etablera en ny token utan användarinteraktion när den aktuella token upphör att gälla.

Dessa scenarier är inte specifika för tokenbaserad autentisering. De är en del av SPAs natur. Ett SPA som använder cookies anropar inte heller ett server-API om autentiseringen cookie tas bort.

När en app utför API-anrop till skyddade resurser måste du vara medveten om följande:

  • Om du vill etablera en ny åtkomsttoken för att anropa API:et kan användaren behöva autentisera igen.
  • Även om klienten har en token som verkar vara giltig kan anropet till servern misslyckas eftersom token har återkallats av användaren.

När appen begär en token finns det två möjliga resultat:

  • Begäran lyckas och appen har en giltig token.
  • Begäran misslyckas och appen måste autentisera användaren igen för att hämta en ny token.

När en tokenbegäran misslyckas måste du bestämma om du vill spara något aktuellt tillstånd innan du utför en omdirigering. Det finns flera metoder för att lagra tillstånd med ökande komplexitetsnivåer:

  • Lagra det aktuella sidtillståndet i sessionslagringen. OnInitializedAsync Under livscykelmetoden (OnInitializedAsync) kontrollerar du om tillståndet kan återställas innan du fortsätter.
  • Lägg till en frågesträngsparameter och använd den som ett sätt att signalera appen att den behöver återhydrera det tidigare sparade tillståndet.
  • Lägg till en frågesträngsparameter med en unik identifierare för att lagra data i sessionslagring utan att riskera kollisioner med andra objekt.

Spara apptillstånd före en autentiseringsåtgärd med sessionslagring

I följande exempel visas hur du:

  • Behåll tillståndet innan du omdirigerar till inloggningssidan.
  • Återställ föregående tillstånd efter autentisering med hjälp av en frågesträngsparameter.
...
@using System.Text.Json
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
@inject IJSRuntime JS
@inject NavigationManager Navigation

<EditForm Model="User" OnSubmit="OnSaveAsync">
    <label>
        First Name: 
        <InputText @bind-Value="User!.Name" />
    </label>
    <label>
        Last Name: 
        <InputText @bind-Value="User!.LastName" />
    </label>
    <button type="submit">Save User</button>
</EditForm>

@code {
    public Profile User { get; set; } = new Profile();

    protected override async Task OnInitializedAsync()
    {
        var currentQuery = new Uri(Navigation.Uri).Query;

        if (currentQuery.Contains("state=resumeSavingProfile"))
        {
            var user = await JS.InvokeAsync<string>("sessionStorage.getItem",
                "resumeSavingProfile");

            if (!string.IsNullOrEmpty(user))
            {
                User = JsonSerializer.Deserialize<Profile>(user);
            }
        }
    }

    public async Task OnSaveAsync()
    {
        var http = new HttpClient();
        http.BaseAddress = new Uri(Navigation.BaseUri);

        var resumeUri = Navigation.Uri + $"?state=resumeSavingProfile";

        var tokenResult = await TokenProvider.RequestAccessToken(
            new AccessTokenRequestOptions
            {
                ReturnUrl = resumeUri
            });

        if (tokenResult.TryGetToken(out var token))
        {
            http.DefaultRequestHeaders.Add("Authorization", 
                $"Bearer {token.Value}");
            await http.PostAsJsonAsync("Save", User);
        }
        else
        {
            await JS.InvokeVoidAsync("sessionStorage.setItem", 
                "resumeSavingProfile", JsonSerializer.Serialize(User));
            Navigation.NavigateTo(tokenResult.InteractiveRequestUrl);
        }
    }

    public class Profile
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
    }
}

Spara apptillstånd före en autentiseringsåtgärd med sessionslagring och en tillståndscontainer

Under en autentiseringsåtgärd finns det fall där du vill spara apptillståndet innan webbläsaren omdirigeras till IP-adressen. Detta kan vara fallet när du använder en tillståndscontainer och vill återställa tillståndet när autentiseringen har slutförts. Du kan använda ett objekt för anpassat autentiseringstillstånd för att bevara appspecifikt tillstånd eller en referens till det och återställa det tillståndet när autentiseringsåtgärden har slutförts. I följande exempel visas metoden.

En tillståndscontainerklass skapas i appen med egenskaper som innehåller appens tillståndsvärden. I följande exempel används containern för att underhålla räknarvärdet för standardprojektmallensBlazorCounter komponent (Counter.razor). Metoder för serialisering och deserialisering av containern baseras på System.Text.Json.

using System.Text.Json;

public class StateContainer
{
    public int CounterValue { get; set; }

    public string GetStateForLocalStorage() => JsonSerializer.Serialize(this);

    public void SetStateFromLocalStorage(string locallyStoredState)
    {
        var deserializedState = 
            JsonSerializer.Deserialize<StateContainer>(locallyStoredState);

        CounterValue = deserializedState.CounterValue;
    }
}

Komponenten Counter använder tillståndscontainern för att underhålla currentCount värdet utanför komponenten:

@page "/counter"
@inject StateContainer State

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    protected override void OnInitialized()
    {
        if (State.CounterValue > 0)
        {
            currentCount = State.CounterValue;
        }
    }

    private void IncrementCount()
    {
        currentCount++;
        State.CounterValue = currentCount;
    }
}

Skapa en ApplicationAuthenticationState från RemoteAuthenticationState. Ange en Id egenskap som fungerar som identifierare för det lokalt lagrade tillståndet.

ApplicationAuthenticationState.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public class ApplicationAuthenticationState : RemoteAuthenticationState
{
    public string? Id { get; set; }
}

Komponenten Authentication (Authentication.razor) sparar och återställer appens tillstånd med hjälp av lokal sessionslagring med StateContainer serialiserings- och deserialiseringsmetoderna och GetStateForLocalStorageSetStateFromLocalStorage :

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IJSRuntime JS
@inject StateContainer State

<RemoteAuthenticatorViewCore Action="Action"
                             TAuthenticationState="ApplicationAuthenticationState"
                             AuthenticationState="AuthenticationState"
                             OnLogInSucceeded="RestoreState"
                             OnLogOutSucceeded="RestoreState" />

@code {
    [Parameter]
    public string? Action { get; set; }

    public ApplicationAuthenticationState AuthenticationState { get; set; } =
        new ApplicationAuthenticationState();

    protected override async Task OnInitializedAsync()
    {
        if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn,
            Action) ||
            RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogOut,
            Action))
        {
            AuthenticationState.Id = Guid.NewGuid().ToString();

            await JS.InvokeVoidAsync("sessionStorage.setItem",
                AuthenticationState.Id, State.GetStateForLocalStorage());
        }
    }

    private async Task RestoreState(ApplicationAuthenticationState state)
    {
        if (state.Id != null)
        {
            var locallyStoredState = await JS.InvokeAsync<string>(
                "sessionStorage.getItem", state.Id);

            if (locallyStoredState != null)
            {
                State.SetStateFromLocalStorage(locallyStoredState);
                await JS.InvokeVoidAsync("sessionStorage.removeItem", state.Id);
            }
        }
    }
}

I det här exemplet används Microsoft Entra (ME-ID) för autentisering. I filen Program:

  • ApplicationAuthenticationState Är konfigurerad som MSAL-typ RemoteAuthenticationState (Microsoft Authentication Library).
  • Statusbehållaren är registrerad i tjänstcontainern.
builder.Services.AddMsalAuthentication<ApplicationAuthenticationState>(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});

builder.Services.AddSingleton<StateContainer>();

Anpassa appvägar

Biblioteket Microsoft.AspNetCore.Components.WebAssembly.Authentication använder de vägar som visas i följande tabell för att representera olika autentiseringstillstånd.

Route Purpose
authentication/login Utlöser en inloggningsåtgärd.
authentication/login-callback Hanterar resultatet av alla inloggningsåtgärder.
authentication/login-failed Visar felmeddelanden när inloggningsåtgärden misslyckas av någon anledning.
authentication/logout Utlöser en utloggningsåtgärd.
authentication/logout-callback Hanterar resultatet av en utloggningsåtgärd.
authentication/logout-failed Visar felmeddelanden när utloggningsåtgärden misslyckas av någon anledning.
authentication/logged-out Anger att användaren har loggat ut.
authentication/profile Utlöser en åtgärd för att redigera användarprofilen.
authentication/register Utlöser en åtgärd för att registrera en ny användare.

De vägar som visas i föregående tabell kan konfigureras via RemoteAuthenticationOptions<TRemoteAuthenticationProviderOptions>.AuthenticationPaths. När du anger alternativ för att tillhandahålla anpassade vägar kontrollerar du att appen har en väg som hanterar varje sökväg.

I följande exempel är alla sökvägar prefixade med /security.

Authentication komponent (Authentication.razor):

@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code{
    [Parameter]
    public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code{
    [Parameter]
    public string Action { get; set; }
}

I filen Program:

builder.Services.AddApiAuthorization(options => { 
    options.AuthenticationPaths.LogInPath = "security/login";
    options.AuthenticationPaths.LogInCallbackPath = "security/login-callback";
    options.AuthenticationPaths.LogInFailedPath = "security/login-failed";
    options.AuthenticationPaths.LogOutPath = "security/logout";
    options.AuthenticationPaths.LogOutCallbackPath = "security/logout-callback";
    options.AuthenticationPaths.LogOutFailedPath = "security/logout-failed";
    options.AuthenticationPaths.LogOutSucceededPath = "security/logged-out";
    options.AuthenticationPaths.ProfilePath = "security/profile";
    options.AuthenticationPaths.RegisterPath = "security/register";
});

Om kravet kräver helt olika sökvägar anger du vägarna enligt beskrivningen tidigare och renderar RemoteAuthenticatorView med en explicit åtgärdsparameter:

@page "/register"

<RemoteAuthenticatorView Action="RemoteAuthenticationActions.Register" />

Du får dela upp användargränssnittet på olika sidor om du väljer att göra det.

Anpassa användargränssnittet för autentisering

RemoteAuthenticatorView innehåller en standarduppsättning med gränssnittsfragment för varje autentiseringstillstånd. Varje tillstånd kan anpassas genom att skicka in en anpassad RenderFragment. Om du vill anpassa den text som visas under den första inloggningsprocessen kan du ändra på RemoteAuthenticatorView följande sätt.

Authentication komponent (Authentication.razor):

@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action">
    <LoggingIn>
        You are about to be redirected to https://login.microsoftonline.com.
    </LoggingIn>
</RemoteAuthenticatorView>

@code{
    [Parameter]
    public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action">
    <LoggingIn>
        You are about to be redirected to https://login.microsoftonline.com.
    </LoggingIn>
</RemoteAuthenticatorView>

@code{
    [Parameter]
    public string Action { get; set; }
}

RemoteAuthenticatorView Har ett fragment som kan användas per autentiseringsväg som visas i följande tabell.

Route Fragment
authentication/login <LoggingIn>
authentication/login-callback <CompletingLoggingIn>
authentication/login-failed <LogInFailed>
authentication/logout <LogOut>
authentication/logout-callback <CompletingLogOut>
authentication/logout-failed <LogOutFailed>
authentication/logged-out <LogOutSucceeded>
authentication/profile <UserProfile>
authentication/register <Registering>

Anpassa användaren

Användare som är bundna till appen kan anpassas.

Anpassa användaren med ett payload-krav

I följande exempel får appens autentiserade användare ett anspråk för var och en amr av användarens autentiseringsmetoder. Anspråket amr identifierar hur ämnet för token autentiserades i Nyttolastanspråk för Microsoft identity platform v1.0. I exemplet används en anpassad användarkontoklass baserat på RemoteUserAccount.

Skapa en klass som utökar RemoteUserAccount klassen. I följande exempel anges AuthenticationMethod egenskapen till användarens matris med amr JSON-egenskapsvärden. AuthenticationMethod fylls i automatiskt av ramverket när användaren autentiseras.

using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("amr")]
    public string[]? AuthenticationMethod { get; set; }
}

Skapa en fabrik som bygger på AccountClaimsPrincipalFactory<TAccount> för att skapa krav baserade på användarens autentiseringsmetoder som lagras i CustomUserAccount.AuthenticationMethod:

using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;

public class CustomAccountFactory(NavigationManager navigation,
    IAccessTokenProviderAccessor accessor)
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account, RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity != null && initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = (ClaimsIdentity)initialUser.Identity;

            if (account.AuthenticationMethod is not null)
            {
                foreach (var value in account.AuthenticationMethod)
                {
                    userIdentity.AddClaim(new Claim("amr", value));
                }
            }
        }

        return initialUser;
    }
}

CustomAccountFactory Registrera autentiseringsleverantören som används. Någon av följande registreringar är giltiga:

  • AddOidcAuthentication:

    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    ...
    
    builder.Services.AddOidcAuthentication<RemoteAuthenticationState, 
        CustomUserAccount>(options =>
        {
            ...
        })
        .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, 
            CustomUserAccount, CustomAccountFactory>();
    
  • AddMsalAuthentication:

    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    ...
    
    builder.Services.AddMsalAuthentication<RemoteAuthenticationState, 
        CustomUserAccount>(options =>
        {
            ...
        })
        .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, 
            CustomUserAccount, CustomAccountFactory>();
    
  • AddApiAuthorization:

    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    ...
    
    builder.Services.AddApiAuthorization<RemoteAuthenticationState, 
        CustomUserAccount>(options =>
        {
            ...
        })
        .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, 
            CustomUserAccount, CustomAccountFactory>();
    

ME-ID säkerhetsgrupper och roller med en anpassad användarkontoklass

Ett annat exempel som fungerar med ME-ID säkerhetsgrupper och ME-ID administratörsroller och en anpassad användarkontoklass finns i ASP.NET Core Blazor WebAssembly med Microsoft Entra ID-grupper och roller.

Prerendering med autentisering

Förberendring av innehåll som kräver autentisering och auktorisering stöds inte just nu. När du har följt vägledningen i något av avsnitten i säkerhetsappen Blazor WebAssembly använder du följande instruktioner för att skapa en app som:

  • Förinstallerar sökvägar för vilka auktorisering inte krävs.
  • Förebygger inte sökvägar för vilka auktorisering krävs.

Client För projektets Program fil ska du dela in common service-registreringar i en separat metod (till exempel skapa en ConfigureCommonServices metod i Client projektet). Vanliga tjänster är de som utvecklaren registrerar för användning av både klient- och serverprojekten.

public static void ConfigureCommonServices(IServiceCollection services)
{
    services.Add...;
}

I filen Program:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
...

builder.Services.AddScoped( ... );

ConfigureCommonServices(builder.Services);

await builder.Build().RunAsync();

Server I projektets Program fil registrerar du följande ytterligare tjänster och anropar ConfigureCommonServices:

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

...

builder.Services.AddRazorPages();
builder.Services.TryAddScoped<AuthenticationStateProvider, 
    ServerAuthenticationStateProvider>();

Client.Program.ConfigureCommonServices(services);

Server I projektets Startup.ConfigureServices metod registrerar du följande ytterligare tjänster och anropar ConfigureCommonServices:

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddRazorPages();
    services.AddScoped<AuthenticationStateProvider, 
        ServerAuthenticationStateProvider>();
    services.AddScoped<SignOutSessionStateManager>();

    Client.Program.ConfigureCommonServices(services);
}

Mer information om ramverksserverautentiseringsprovidern Blazor (ServerAuthenticationStateProvider) finns i ASP.NET Core-autentisering Blazor och -auktorisering.

I projektets Server fil, ersätt Pages/_Host.cshtml Tag Helper (Component) med följande:

<div id="app">
    @if (HttpContext.Request.Path.StartsWithSegments("/authentication"))
    {
        <component type="typeof({CLIENT APP ASSEMBLY NAME}.App)" 
            render-mode="WebAssembly" />
    }
    else
    {
        <component type="typeof({CLIENT APP ASSEMBLY NAME}.App)" 
            render-mode="WebAssemblyPrerendered" />
    }
</div>

I föregående exempel:

  • Platshållaren {CLIENT APP ASSEMBLY NAME} är klientappens sammansättningsnamn (till exempel BlazorSample.Client).
  • Villkorsstyrd kontroll för sökvägssegmentet /authentication :
    • Undviker prerendering (render-mode="WebAssembly") för autentiseringssökvägar.
    • Prerenders (render-mode="WebAssemblyPrerendered") för icke-autentiseringssökvägar.

Alternativ för värdbaserade appar och tredjepartsinloggningsleverantörer

När du autentiserar och auktoriserar en värdbaserad Blazor WebAssembly app med en tredjepartsleverantör finns det flera alternativ för att autentisera användaren. Vilken du väljer beror på ditt scenario.

För mer information, se Spara ytterligare krav och token från externa leverantörer i ASP.NET Core.

Autentisera användare för att endast anropa skyddade API:er från tredje part

Autentisera användaren med ett OAuth-flöde på klientsidan mot API-providern från tredje part:

builder.services.AddOidcAuthentication(options => { ... });

I det här scenariot:

  • Servern som är värd för appen spelar ingen roll.
  • API:er på servern kan inte skyddas.
  • Appen kan bara anropa skyddade API:er från tredje part.

Autentisera användare med en tredjepartsleverantör och anropa skyddade API:er på värdservern och tredje part

Konfigurera Identity med en tredjepartsinloggningsprovider. Hämta de token som krävs för api-åtkomst från tredje part och lagra dem.

När en användare loggar in Identity samlar in åtkomst- och uppdateringstoken som en del av autentiseringsprocessen. Då finns det ett par metoder för att göra API-anrop till API:er från tredje part.

Använd en serveråtkomsttoken för att hämta åtkomsttoken från tredje part

Använd åtkomsttoken som genereras på servern för att hämta åtkomsttoken från tredje part från en server-API-slutpunkt. Därifrån använder du åtkomsttoken från tredje part för att anropa API-resurser från tredje part direkt från Identity klienten.

Vi rekommenderar inte den här metoden. Den här metoden kräver att åtkomsttoken från tredje part behandlas som om den genererades för en offentlig klient. I OAuth-termer har den offentliga appen ingen klienthemlighet eftersom den inte kan lita på att lagra hemligheter på ett säkert sätt och åtkomsttoken skapas för en konfidentiell klient. En konfidentiell klient är en klient som har en klienthemlighet och antas kunna lagra hemligheter på ett säkert sätt.

  • Åtkomsttoken från tredje part kan beviljas ytterligare omfång för att utföra känsliga åtgärder baserat på det faktum att tredje part avgav token för en mer betrodd klient.
  • På samma sätt bör uppdateringstoken inte utfärdas till en klient som inte är betrodd, eftersom det ger klienten obegränsad åtkomst om inte andra begränsningar tillämpas.

Göra API-anrop från klienten till server-API:et för att anropa API:er från tredje part

Gör ett API-anrop från klienten till server-API:et. Från servern hämtar du åtkomsttoken för API-resursen från tredje part och utfärdar det anrop som krävs.

Vi rekommenderar den här metoden. Även om den här metoden kräver ett extra nätverkshopp via servern för att anropa ett API från tredje part, resulterar det i slutänden i en säkrare upplevelse:

  • Servern kan lagra uppdateringstoken och se till att appen inte förlorar åtkomsten till resurser från tredje part.
  • Appen kan inte läcka åtkomsttoken från servern som kan innehålla mer känsliga behörigheter.

Använda OpenID Connect-slutpunkter (OIDC) v2.0

Autentiseringsbiblioteket och Blazor projektmallarna använder OpenID Connect (OIDC) v1.0-slutpunkter. Om du vill använda en v2.0-slutpunkt konfigurerar du alternativet JWT Bearer JwtBearerOptions.Authority . I följande exempel konfigureras ME-ID för v2.0 genom att ett v2.0 segment läggs till i Authority egenskapen:

using Microsoft.AspNetCore.Authentication.JwtBearer;

...

builder.Services.Configure<JwtBearerOptions>(
    JwtBearerDefaults.AuthenticationScheme, 
    options =>
    {
        options.Authority += "/v2.0";
    });

Du kan också göra inställningen i appinställningarna (appsettings.json) filen:

{
  "Local": {
    "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/",
    ...
  }
}

Om det inte är lämpligt att fästa ett segment på auktoriteten för appens OIDC-leverantör, till exempel med icke-ME-ID-leverantörer, anger du egenskapen Authority direkt. Ange antingen egenskapen i JwtBearerOptions eller i appinställningsfilen (appsettings.json) med Authority nyckeln.

Listan över anspråk i ID-token ändras för v2.0-slutpunkter. Microsofts dokumentation om ändringarna har dragits tillbaka, men vägledning om anspråken i en ID-token finns i -referensen för ID-tokenanspråk.

Konfigurera och använda gRPC i komponenter

Så här konfigurerar du en Blazor WebAssembly app för att använda ASP.NET Core gRPC-ramverket:

  • Aktivera gRPC-Web på servern. Mer information finns i gRPC-Web i ASP.NET Core gRPC-appar.
  • Registrera gRPC-tjänster för appens meddelandehanterare. I följande exempel konfigureras appens auktoriseringsmeddelandehanterare för att använda GreeterClient (i -filen).

Note

Prerendering är aktiverat som standard i Blazor Web Apps, så du måste ta hänsyn till komponentåtergivningen först från servern och sedan från klienten. Alla förberedda tillstånd bör överföras till klienten så att det kan återanvändas. Mer information finns i ASP.NET Core Blazor prerendered state persistence.

Note

Förrendering är aktiverat som standard i värdbaserade Blazor WebAssembly appar, så du måste först ta hänsyn till komponentåtergivningen från servern och sedan från klienten. Alla förberedda tillstånd bör överföras till klienten så att det kan återanvändas. Mer information finns i Integrera ASP.NET Core-komponenter Razor med MVC eller Razor Sidor i värdbaserade Blazor WebAssembly lösningar.

using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;

...

builder.Services.AddScoped(sp =>
{
    var baseAddressMessageHandler = 
        sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>();
    baseAddressMessageHandler.InnerHandler = new HttpClientHandler();
    var grpcWebHandler = 
        new GrpcWebHandler(GrpcWebMode.GrpcWeb, baseAddressMessageHandler);
    var channel = GrpcChannel.ForAddress(builder.HostEnvironment.BaseAddress, 
        new GrpcChannelOptions { HttpHandler = grpcWebHandler });

    return new Greeter.GreeterClient(channel);
});

En komponent i klientappen kan göra gRPC-anrop med hjälp av gRPC-klienten (Grpc.razor):

@page "/grpc"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject Greeter.GreeterClient GreeterClient

<h1>Invoke gRPC service</h1>

<p>
    <input @bind="name" placeholder="Type your name" />
    <button @onclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>

Server response: <strong>@serverResponse</strong>

@code {
    private string name = "Bert";
    private string? serverResponse;

    private async Task GetGreeting()
    {
        try
        {
            var request = new HelloRequest { Name = name };
            var reply = await GreeterClient.SayHelloAsync(request);
            serverResponse = reply.Message;
        }
        catch (Grpc.Core.RpcException ex)
            when (ex.Status.DebugException is 
                AccessTokenNotAvailableException tokenEx)
        {
            tokenEx.Redirect();
        }
    }
}

Om du vill använda egenskapen Status.DebugException använder du Grpc.Net.Client version 2.30.0 eller senare.

Mer information finns i gRPC-Web i ASP.NET Core gRPC-appar.

Ersätt AuthenticationService implementeringen

Följande underavsnitt förklarar hur du ersätter:

  • Vilken som helst JavaScript-implementering AuthenticationService.
  • Microsoft Authentication Library för JavaScript (MSAL.js).

Ersätt alla JavaScript-implementeringar AuthenticationService

Skapa ett JavaScript-bibliotek för att hantera din anpassade autentiseringsinformation.

Warning

Vägledningen i det här avsnittet är en implementeringsinformation för standardinställningen RemoteAuthenticationService<TRemoteAuthenticationState,TAccount,TProviderOptions>. TypeScript-koden i det här avsnittet gäller specifikt för ASP.NET Core i .NET 7 och kan komma att ändras utan föregående meddelande i kommande versioner av ASP.NET Core.

// .NET makes calls to an AuthenticationService object in the Window.
declare global {
  interface Window { AuthenticationService: AuthenticationService }
}

export interface AuthenticationService {
  // Init is called to initialize the AuthenticationService.
  public static init(settings: UserManagerSettings & AuthorizeServiceSettings, logger: any) : Promise<void>;

  // Gets the currently authenticated user.
  public static getUser() : Promise<{[key: string] : string }>;

  // Tries to get an access token silently.
  public static getAccessToken(options: AccessTokenRequestOptions) : Promise<AccessTokenResult>;

  // Tries to sign in the user or get an access token interactively.
  public static signIn(context: AuthenticationContext) : Promise<AuthenticationResult>;

  // Handles the sign-in process when a redirect is used.
  public static async completeSignIn(url: string) : Promise<AuthenticationResult>;

  // Signs the user out.
  public static signOut(context: AuthenticationContext) : Promise<AuthenticationResult>;

  // Handles the signout callback when a redirect is used.
  public static async completeSignOut(url: string) : Promise<AuthenticationResult>;
}

// The rest of these interfaces match their C# definitions.

export interface AccessTokenRequestOptions {
  scopes: string[];
  returnUrl: string;
}

export interface AccessTokenResult {
  status: AccessTokenResultStatus;
  token?: AccessToken;
}

export interface AccessToken {
  value: string;
  expires: Date;
  grantedScopes: string[];
}

export enum AccessTokenResultStatus {
  Success = 'Success',
  RequiresRedirect = 'RequiresRedirect'
}

export enum AuthenticationResultStatus {
  Redirect = 'Redirect',
  Success = 'Success',
  Failure = 'Failure',
  OperationCompleted = 'OperationCompleted'
};

export interface AuthenticationResult {
  status: AuthenticationResultStatus;
  state?: unknown;
  message?: string;
}

export interface AuthenticationContext {
  state?: unknown;
  interactiveRequest: InteractiveAuthenticationRequest;
}

export interface InteractiveAuthenticationRequest {
  scopes?: string[];
  additionalRequestParameters?: { [key: string]: any };
};

Du kan importera biblioteket genom att ta bort den ursprungliga <script> taggen och lägga till en <script> tagg som läser in det anpassade biblioteket. I följande exempel visas hur du ersätter standardtaggen <script> med ett som läser in ett bibliotek med namnet CustomAuthenticationService.js från wwwroot/js mappen.

In wwwroot/index.html före skriptet Blazor (_framework/blazor.webassembly.js) inuti den avslutande </body> taggen:

- <script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
+ <script src="js/CustomAuthenticationService.js"></script>

Mer information AuthenticationService.ts finns på GitHub-lagringsplatsendotnet/aspnetcore.

Note

Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Välj bland grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).

Ersätt Microsoft Authentication Library för JavaScript (MSAL.js)

Om en app kräver en anpassad version av Microsoft Authentication Library för JavaScript (MSAL.js)utför du följande steg:

  1. Bekräfta att systemet har den senaste utvecklaren .NET SDK eller hämta och installera den senaste utvecklar-SDK:t från .NET SDK: Installers och Binaries. Konfiguration av interna NuGet-feeds krävs inte för det här scenariot.
  2. Konfigurera dotnet/aspnetcore GitHub-lagringsplatsen för utveckling enligt dokumentationen i Skapa ASP.NET Core från källa. Förgrena och klona eller ladda ned ett ZIP-arkiv för dotnet/aspnetcore GitHub-lagringsplatsen.
  3. src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json Öppna filen och ange önskad version av @azure/msal-browser. En lista över utgivna versioner finns på @azure/msal-browser npm-webbplatsen och väljer fliken Versioner .
  4. Authentication.Msal Skapa projektet i src/Components/WebAssembly/Authentication.Msal/src mappen med yarn build kommandot i ett kommandogränssnitt.
  5. Om appen använder komprimerade tillgångar (Brotli/Gzip) komprimerar du Interop/dist/Release/AuthenticationService.js filen.
  6. Kopiera AuthenticationService.js-filen och komprimerade versioner (.br/.gz) av filen, om de har producerats, från Interop/dist/Release-katalogen till appens publish/wwwroot/_content/Microsoft.Authentication.WebAssembly.Msal-katalog i appens publicerade resurser.

Skicka anpassade provideralternativ

Definiera en klass för att skicka data till det underliggande JavaScript-biblioteket.

Important

Klassens struktur måste matcha vad biblioteket förväntar sig när JSON serialiseras med System.Text.Json.

I följande exempel visas en ProviderOptions klass med attribut somJsonPropertyName matchar förväntningarna för ett hypotetiskt anpassat providerbibliotek:

public class ProviderOptions
{
    public string? Authority { get; set; }
    public string? MetadataUrl { get; set; }
    
    [JsonPropertyName("client_id")]
    public string? ClientId { get; set; }
    
    public IList<string> DefaultScopes { get; set; } = [ "openid", "profile" ];
        
    [JsonPropertyName("redirect_uri")]
    public string? RedirectUri { get; set; }
    
    [JsonPropertyName("post_logout_redirect_uri")]
    public string? PostLogoutRedirectUri { get; set; }
    
    [JsonPropertyName("response_type")]
    public string? ResponseType { get; set; }
    
    [JsonPropertyName("response_mode")]
    public string? ResponseMode { get; set; }
}

Registrera provideralternativen i DI-systemet och konfigurera lämpliga värden:

builder.Services.AddRemoteAuthentication<RemoteAuthenticationState, RemoteUserAccount,
    ProviderOptions>(options => {
        options.ProviderOptions.Authority = "...";
        options.ProviderOptions.MetadataUrl = "...";
        options.ProviderOptions.ClientId = "...";
        options.ProviderOptions.DefaultScopes = [ "openid", "profile", "myApi" ];
        options.ProviderOptions.RedirectUri = "https://localhost:5001/authentication/login-callback";
        options.ProviderOptions.PostLogoutRedirectUri = "https://localhost:5001/authentication/logout-callback";
        options.ProviderOptions.ResponseType = "...";
        options.ProviderOptions.ResponseMode = "...";
    });

I föregående exempel anges omdirigerings-URI:er med vanliga strängliteraler. Följande alternativ är tillgängliga:

  • TryCreatemed :IWebAssemblyHostEnvironment.BaseAddress

    Uri.TryCreate(
        $"{builder.HostEnvironment.BaseAddress}authentication/login-callback", 
        UriKind.Absolute, out var redirectUri);
    options.RedirectUri = redirectUri;
    
  • Konfiguration av värdbyggare:

    options.RedirectUri = builder.Configuration["RedirectUri"];
    

    wwwroot/appsettings.json:

    {
      "RedirectUri": "https://localhost:5001/authentication/login-callback"
    }
    

Ytterligare resurser