ASP.NET Core Blazor WebAssembly ek güvenlik senaryoları

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Bu makalede, uygulamalar için Blazor WebAssembly ek güvenlik senaryoları açıklanmaktadır.

Giden isteklere belirteç ekleme

AuthorizationMessageHandlerDelegatingHandler erişim belirteçlerini işlemek için kullanılır. Belirteçler, çerçeve tarafından kaydedilen hizmet kullanılarak IAccessTokenProvider alınır. Belirteç alınamazsa, bir AccessTokenNotAvailableException oluşturulur. AccessTokenNotAvailableException, erişim belirtecinin yenilenmesine AccessTokenResult.InteractiveRequestUrl izin vermek için verilen AccessTokenResult.InteractionOptions öğesini kullanmaya giden bir Redirect yönteme sahiptir.

Kolaylık olması için, çerçeve uygulamanın temel adresiyle önceden yapılandırılmış olan bir yetkili URL sağlar BaseAddressAuthorizationMessageHandler . Erişim belirteçleri yalnızca istek URI'sinin uygulamanın temel URI'sinde olması halinde eklenir. Giden istek URI'leri uygulamanın temel URI'sinde olmadığında, özel bir sınıf kullanın (önerilen) veya yapılandırınAuthorizationMessageHandler.AuthorizationMessageHandler

Not

Sunucu API erişimi için istemci uygulama yapılandırmasına ek olarak, istemci ve sunucu aynı temel adreste olmadığında sunucu API'sinin çıkış noktaları arası isteklere (CORS) de izin vermesi gerekir. Sunucu tarafı CORS yapılandırması hakkında daha fazla bilgi için bu makalenin devamındaki Çıkış Noktaları Arası Kaynak Paylaşımı (CORS) bölümüne bakın.

Aşağıdaki örnekte:

Aşağıdaki örnekte, HttpClientFactoryServiceCollectionExtensions.AddHttpClient içindeki Microsoft.Extensions.Httpbir uzantıdır. Paketi, henüz başvurmayan bir uygulamaya ekleyin.

Not

.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri)paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

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

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssemblybir çözüm için istek URI'leri varsayılan olarak uygulamanın temel URI'sindedir. Bu nedenle, IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)) proje şablonundan oluşturulan bir uygulamada öğesine atanır HttpClient.BaseAddress .

Yapılandırılan HttpClient , deseni kullanarak try-catch yetkili isteklerde bulunmak için kullanılır:

@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();
    }
}

Özel kimlik doğrulama isteği senaryoları

Aşağıdaki senaryolarda, kimlik doğrulama isteklerini özelleştirme ve kimlik doğrulama seçeneklerinden oturum açma yolunun nasıl edinileceği gösterilmektedir.

Oturum açma işlemini özelleştirme

Yeni bir örneğinde bir veya daha fazla kez aşağıdaki yöntemlerle bir oturum açma isteğine InteractiveRequestOptionsyönelik ek parametreleri yönetin:

Aşağıdaki LoginDisplay bileşen örneğinde, oturum açma isteğine ek parametreler eklenir:

  • prompt olarak ayarlanır login: Kullanıcıyı bu istekte kimlik bilgilerini girmeye zorlar ve çoklu oturum açmayı olumsuzlar.
  • loginHint olarak ayarlanır peter@contoso.com: Kullanıcının oturum açma sayfasının peter@contoso.comkullanıcı adı/e-posta adresi alanını olarak önceden doldurur. Uygulamalar bu parametreyi genellikle yeniden kimlik doğrulaması sırasında kullanır ve talebi kullanarak preferred_username kullanıcı adını önceki bir oturum açmadan ayıklar.

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

Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

Bir belirteci etkileşimli olarak almadan önce seçenekleri özelleştirme

Oluşursa AccessTokenNotAvailableException , yeni bir kimlik sağlayıcısı erişim belirteci isteği için ek parametreleri yeni bir örneğinde InteractiveRequestOptionsbir veya daha fazla kez aşağıdaki yöntemlerle yönetin:

Web API'si aracılığıyla ON verilerini alan JSaşağıdaki örnekte, erişim belirteci kullanılamıyorsa (AccessTokenNotAvailableException oluşturulduysa) yeniden yönlendirme isteğine ek parametreler eklenir:

  • prompt olarak ayarlanır login: Kullanıcıyı bu istekte kimlik bilgilerini girmeye zorlar ve çoklu oturum açmayı olumsuzlar.
  • loginHint olarak ayarlanır peter@contoso.com: Kullanıcının oturum açma sayfasının peter@contoso.comkullanıcı adı/e-posta adresi alanını olarak önceden doldurur. Uygulamalar bu parametreyi genellikle yeniden kimlik doğrulaması sırasında kullanır ve talebi kullanarak preferred_username kullanıcı adını önceki bir oturum açmadan ayıklar.
try
{
    var examples = await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");

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

Yukarıdaki örnekte aşağıdakiler varsayılır:

Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

IAccessTokenProvider kullanırken seçenekleri özelleştirme

kullanırken belirteç alma işlemi başarısız olursa IAccessTokenProvider, yeni bir kimlik sağlayıcısı erişim belirteci isteği için ek parametreleri yeni bir örneğinde InteractiveRequestOptionsbir veya daha fazla kez aşağıdaki yöntemlerle yönetin:

Kullanıcı için erişim belirteci almayı deneyen aşağıdaki örnekte, belirteç alma girişimi çağrıldığında TryGetToken başarısız olursa oturum açma isteğine ek parametreler eklenir:

  • prompt olarak ayarlanır login: Kullanıcıyı bu istekte kimlik bilgilerini girmeye zorlar ve çoklu oturum açmayı olumsuzlar.
  • loginHint olarak ayarlanır peter@contoso.com: Kullanıcının oturum açma sayfasının peter@contoso.comkullanıcı adı/e-posta adresi alanını olarak önceden doldurur. Uygulamalar bu parametreyi genellikle yeniden kimlik doğrulaması sırasında kullanır ve talebi kullanarak preferred_username kullanıcı adını önceki bir oturum açmadan ayıklar.
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);
}

Yukarıdaki örnekte aşağıdakiler varsayılır:

Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

Özel dönüş URL'si ile oturum kapatma

Aşağıdaki örnek kullanıcının oturumunu günlüğe kaydeder ve kullanıcıyı /goodbye uç noktaya döndürür:

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

Kimlik doğrulaması seçeneklerinden oturum açma yolunu alma

Yapılandırılan oturum açma yolunu uygulamasından RemoteAuthenticationOptionsalın:

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

Yukarıdaki örnekte aşağıdakiler varsayılır:

Özel AuthorizationMessageHandler sınıf

Bu bölümdeki bu kılavuz, uygulamanın temel URI'sinde olmayan URI'lere giden istekte bulunan istemci uygulamaları için önerilir.

Aşağıdaki örnekte, özel bir sınıf için olarak DelegatingHandlerHttpClientkullanılmak üzere genişletirAuthorizationMessageHandler. ConfigureHandler bir erişim belirteci kullanarak giden HTTP isteklerini yetkilendirmek için bu işleyiciyi yapılandırıyor. Erişim belirteci yalnızca yetkili URL'lerden en az biri istek URI'sinin (HttpRequestMessage.RequestUri) temeliyse eklenir.

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: new[] { "https://api.contoso.com/v1.0" },
            scopes: new[] { "example.read", "example.write" });
    }
}

Önceki kodda kapsamlar example.read ve example.write genel örnekler, belirli bir sağlayıcı için geçerli kapsamları yansıtmak üzere tasarlanmamıştır.

Program dosyasında, CustomAuthorizationMessageHandler geçici bir hizmet olarak kaydedilir ve adlandırılmış HttpClientbir tarafından yapılan giden HttpResponseMessage örnekler için olarak DelegatingHandler yapılandırılır.

Aşağıdaki örnekte, HttpClientFactoryServiceCollectionExtensions.AddHttpClient içindeki Microsoft.Extensions.Httpbir uzantıdır. Paketi, henüz başvurmayan bir uygulamaya ekleyin.

Not

.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri)paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

builder.Services.AddTransient<CustomAuthorizationMessageHandler>();

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

Not

Yukarıdaki örnekte , CustomAuthorizationMessageHandlerDelegatingHandler için AddHttpMessageHandlergeçici bir hizmet olarak kaydedilir. kendi DI kapsamlarını yöneten için IHttpClientFactorygeçici kayıt önerilir. Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm için varsayılan IWebAssemblyHostEnvironment.BaseAddressnew Uri(builder.HostEnvironment.BaseAddress)olarak () öğesine HttpClient.BaseAddress atanır.

Yapılandırılan HttpClient , deseni kullanarak try-catch yetkili isteklerde bulunmak için kullanılır. İstemcinin (Microsoft.Extensions.Http paket) ile CreateClient oluşturulduğu yerde, HttpClient sunucu API'sine istekte bulunurken erişim belirteçlerini içeren örnekler sağlanır. İstek URI'si, aşağıdaki örnekteExampleAPIMethod () olduğu gibi göreli bir URI ise, istemci uygulamasının BaseAddress isteği ne zaman yaptığı ile birleştirilir:

@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();
        }
    }
}

Yapılandırmak AuthorizationMessageHandler

AuthorizationMessageHandler , yöntemini kullanarak yetkili URL'ler, kapsamlar ve bir dönüş URL'si ConfigureHandler ile yapılandırılabilir. ConfigureHandler bir erişim belirteci kullanarak giden HTTP isteklerini yetkilendirmek için işleyiciyi yapılandırıyor. Erişim belirteci yalnızca yetkili URL'lerden en az biri istek URI'sinin (HttpRequestMessage.RequestUri) temeliyse eklenir. İstek URI'si göreli bir URI ise, ile BaseAddressbirleştirilir.

Aşağıdaki örnekte dosyasında AuthorizationMessageHandler bir HttpClientProgram yapılandırılır:

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

...

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

Önceki kodda kapsamlar example.read ve example.write genel örnekler, belirli bir sağlayıcı için geçerli kapsamları yansıtmak üzere tasarlanmamıştır.

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm için, IWebAssemblyHostEnvironment.BaseAddress varsayılan olarak aşağıdakilere atanır:

Yazılı HttpClient

Tek bir sınıf içindeki tüm HTTP ve belirteç alma sorunlarını işleyen, türü belirlenmiş bir istemci tanımlanabilir.

WeatherForecastClient.cs:

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

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

    public WeatherForecastClient(HttpClient http)
    {
        this.http = http;
    }

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

        return forecasts ?? Array.Empty<WeatherForecast>();
    }
}
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using static {ASSEMBLY NAME}.Data;

public class WeatherForecastClient
{
    private readonly HttpClient http;
    private WeatherForecast[] forecasts;

    public WeatherForecastClient(HttpClient http)
    {
        this.http = http;
    }

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

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

Yukarıdaki örnekte türü, WeatherForecast hava durumu tahmin verilerini tutan statik bir sınıftır. Yer tutucu {ASSEMBLY NAME} , uygulamanın derleme adıdır (örneğin, using static BlazorSample.Data;).

Aşağıdaki örnekte, HttpClientFactoryServiceCollectionExtensions.AddHttpClient içindeki Microsoft.Extensions.Httpbir uzantıdır. Paketi, henüz başvurmayan bir uygulamaya ekleyin.

Not

.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri)paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

Program dosyasında:

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>();

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm için varsayılan IWebAssemblyHostEnvironment.BaseAddressnew Uri(builder.HostEnvironment.BaseAddress)olarak () öğesine HttpClient.BaseAddress atanır.

Hava durumu verilerini getiren bir bileşende:

@inject WeatherForecastClient Client

...

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

İşleyiciyi HttpClient yapılandırma

İşleyici, giden HTTP istekleri için ile ConfigureHandler daha fazla yapılandırılabilir.

Aşağıdaki örnekte, HttpClientFactoryServiceCollectionExtensions.AddHttpClient içindeki Microsoft.Extensions.Httpbir uzantıdır. Paketi, henüz başvurmayan bir uygulamaya ekleyin.

Not

.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri)paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

Program dosyasında:

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

Önceki kodda kapsamlar example.read ve example.write genel örnekler, belirli bir sağlayıcı için geçerli kapsamları yansıtmak üzere tasarlanmamıştır.

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm için, IWebAssemblyHostEnvironment.BaseAddress varsayılan olarak aşağıdakilere atanır:

Güvenli bir varsayılan istemciye sahip bir uygulamada kimliği doğrulanmamış veya yetkisiz web API'si istekleri

Normalde güvenli bir varsayılan HttpClient kullanan bir uygulama, adlandırılmış HttpClientbir yapılandırarak kimliği doğrulanmamış veya yetkisiz web API'leri istekleri de yapabilir.

Aşağıdaki örnekte, HttpClientFactoryServiceCollectionExtensions.AddHttpClient içindeki Microsoft.Extensions.Httpbir uzantıdır. Paketi, henüz başvurmayan bir uygulamaya ekleyin.

Not

.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri)paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

Program dosyasında:

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

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm için varsayılan IWebAssemblyHostEnvironment.BaseAddressnew Uri(builder.HostEnvironment.BaseAddress)olarak () öğesine HttpClient.BaseAddress atanır.

Önceki kayıt, mevcut güvenli varsayılan HttpClient kayda ek olarak yapılır.

Bir bileşen, kimliği doğrulanmamış veya yetkisiz isteklerde bulunmak için öğesini (Microsoft.Extensions.Http paketinden IHttpClientFactory ) oluştururHttpClient:

@inject IHttpClientFactory ClientFactory

...

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

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

        ...
    }
}

Not

Yukarıdaki örnekte sunucu API'sindeki ExampleNoAuthenticationController denetleyici özniteliğiyle [Authorize]işaretlenmemiştir.

Varsayılan HttpClient örnek olarak güvenli istemci mi yoksa güvenli olmayan bir istemci mi kullanılacağına karar geliştiriciye bağlı. Bu kararı vermenin bir yolu, uygulamanın iletişimde olduğu kimliği doğrulanmış ve kimliği doğrulanmamış uç noktaların sayısını göz önünde bulundurmaktır. Uygulamanın isteklerinin çoğu API uç noktalarının güvenliğini sağlamaksa, varsayılan olarak kimliği doğrulanmış HttpClient örneği kullanın. Aksi takdirde, kimliği doğrulanmamış HttpClient örneği varsayılan olarak kaydedin.

kullanmak IHttpClientFactory için alternatif bir yaklaşım anonim uç noktalara kimliği doğrulanmamış erişim için türlenmiş bir istemci oluşturmaktır.

Ek erişim belirteçleri isteme

Erişim belirteçleri çağrılarak IAccessTokenProvider.RequestAccessTokenel ile alınabilir. Aşağıdaki örnekte, varsayılan HttpClientiçin bir uygulama tarafından ek bir kapsam gereklidir. Microsoft Authentication Library (MSAL) örneği kapsamı ile MsalProviderOptionsyapılandırıyor:

Program dosyasında:

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

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

{CUSTOM SCOPE 1} Yukarıdaki örnekteki ve {CUSTOM SCOPE 2} yer tutucuları özel kapsamlardır.

Not

AdditionalScopesToConsent bir kullanıcı Microsoft Azure'da kayıtlı bir uygulamayı ilk kez kullandığında Microsoft Entra Id onay kullanıcı arabirimi aracılığıyla Microsoft Graph için temsilci kullanıcı izinleri sağlayamaz. Daha fazla bilgi için bkz . ASP.NET Core Blazor WebAssemblyile Graph API'sini kullanma.

yöntemi, IAccessTokenProvider.RequestAccessToken bir uygulamanın belirli bir kapsam kümesiyle erişim belirteci sağlamasına olanak tanıyan bir aşırı yükleme sağlar.

Bir Razor bileşende:

@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))
{
    ...
}

{CUSTOM SCOPE 1} Yukarıdaki örnekteki ve {CUSTOM SCOPE 2} yer tutucuları özel kapsamlardır.

AccessTokenResult.TryGetToken Döndürür:

  • truetoken ile birlikte kullanın.
  • false belirteci alınmazsa.

Çıkış Noktaları Arası Kaynak Paylaşma (CORS)

CORS isteklerinde kimlik bilgileri (yetkilendirme cookies/üst bilgileri) gönderirken, Authorization üst bilgi cors ilkesi tarafından izin verilmelidir.

Aşağıdaki ilke şunlar için yapılandırmayı içerir:

  • İstek çıkış noktaları (http://localhost:5000, https://localhost:5001).
  • Herhangi bir yöntem (fiil).
  • Content-Type ve Authorization üst bilgileri seçin. Özel üst bilgi (örneğin, x-custom-header) izin vermek için çağrısı WithHeadersyaparken üst bilgiyi listeleyin.
  • İstemci tarafı JavaScript kodu tarafından ayarlanan kimlik bilgileri (credentials özelliği olarak includeayarlanır).
app.UseCors(policy => 
    policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
        .AllowAnyMethod()
        .WithHeaders(HeaderNames.ContentType, HeaderNames.Authorization, 
            "x-custom-header")
        .AllowCredentials());

Proje şablonunu temel alan barındırılan BlazorBlazor WebAssembly bir çözüm, istemci ve sunucu uygulamaları için aynı temel adresi kullanır. İstemci uygulamasının URI'leri HttpClient.BaseAddress varsayılan olarak URI'sine builder.HostEnvironment.BaseAddress ayarlanır. Barındırılan çözümün varsayılan yapılandırmasında CORS yapılandırması gerekli değildir.Blazor Sunucu projesi tarafından barındırılan ve sunucu uygulamasının temel adresini paylaşmayan ek istemci uygulamaları, sunucu projesinde CORS yapılandırması gerektirir.

Daha fazla bilgi için bkz . ASP.NET Core'da Çıkış Noktaları Arası İstekleri (CORS) etkinleştirme ve örnek uygulamanın HTTP İstek Sınayıcısı bileşeni (Components/HTTPRequestTester.razor).

Belirteç isteği hatalarını işleme

Tek sayfalı bir uygulama (SPA) OpenID Bağlan (OIDC) kullanarak kullanıcının kimliğini doğruladığında, kimlik doğrulama durumu SPA içinde yerel olarak ve Identity Kullanıcının kimlik bilgilerini sağlamasının bir sonucu olarak ayarlanan bir oturum cookie biçiminde Sağlayıcıda (IP) korunur.

IP'nin kullanıcı için yaydığı belirteçler genellikle kısa süreler için geçerlidir ve bu nedenle istemci uygulamasının düzenli olarak yeni belirteçleri getirmesi gerekir. Aksi takdirde, verilen belirteçlerin süresi dolduktan sonra kullanıcı oturumu kapatılır. Çoğu durumda OIDC istemcileri, IP içinde tutulan kimlik doğrulama durumu veya "oturum" sayesinde kullanıcının yeniden kimlik doğrulamasına gerek kalmadan yeni belirteçler sağlar.

Bazı durumlarda istemci kullanıcı etkileşimi olmadan belirteç alamaz, örneğin, herhangi bir nedenden dolayı kullanıcının IP'den açıkça oturumu kapattığı durumlar olabilir. Bu senaryo, bir kullanıcı ziyaret https://login.microsoftonline.com edip oturumu kapatıyorsa oluşur. Bu senaryolarda uygulama kullanıcının oturumunu kapattığını hemen bilmez. İstemcinin tuttuğu belirteçler artık geçerli olmayabilir. Ayrıca istemci, geçerli belirtecin süresi dolduktan sonra kullanıcı etkileşimi olmadan yeni bir belirteç sağlayamaz.

Bu senaryolar belirteç tabanlı kimlik doğrulamasına özgü değildir. BUNLAR SPA'ların doğasının bir parçasıdır. Kimlik doğrulaması cookie kaldırılırsa s kullanan cookiebir SPA da sunucu API'sini çağıramazsınız.

Bir uygulama korumalı kaynaklara API çağrıları gerçekleştirdiğinde aşağıdakilere dikkat etmeniz gerekir:

  • API'yi çağırmak üzere yeni bir erişim belirteci sağlamak için kullanıcının yeniden kimlik doğrulaması gerekebilir.
  • İstemcinin geçerli gibi görünen bir belirteci olsa bile, belirteç kullanıcı tarafından iptal edildiğinden sunucu çağrısı başarısız olabilir.

Uygulama belirteç istediğinde iki olası sonuç vardır:

  • İstek başarılı olur ve uygulamanın geçerli bir belirteci vardır.
  • İstek başarısız olur ve uygulamanın yeni bir belirteç almak için kullanıcının kimliğini yeniden doğrulaması gerekir.

Belirteç isteği başarısız olduğunda, yeniden yönlendirme gerçekleştirmeden önce herhangi bir geçerli durumu kaydetmek isteyip istemediğinize karar vermeniz gerekir. Artan karmaşıklık düzeyleriyle durumu depolamak için çeşitli yaklaşımlar vardır:

  • Geçerli sayfa durumunu oturum depolama alanında depolayın. OnInitializedAsync Yaşam döngüsü yöntemi ()OnInitializedAsync sırasında devam etmeden önce durumun geri yüklenip yüklenmediğini denetleyin.
  • Bir sorgu dizesi parametresi ekleyin ve bunu uygulamaya daha önce kaydedilen durumu yeniden nemlendirmesi gerektiğini belirten bir yol olarak kullanın.
  • Diğer öğelerle çakışma riskini göze almadan verileri oturum depolama alanında depolamak için benzersiz tanımlayıcıya sahip bir sorgu dizesi parametresi ekleyin.

Oturum depolama ile kimlik doğrulama işleminden önce uygulama durumunu kaydetme

Aşağıdaki örnekte şunların nasıl yapılacağını gösterilmektedir:

  • Oturum açma sayfasına yeniden yönlendirmeden önce durumu koruyun.
  • Sorgu dizesi parametresini kullanarak kimlik doğrulamasından sonra önceki durumu kurtarın.
...
@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; }
    }
}

Oturum depolama ve durum kapsayıcısı ile kimlik doğrulama işleminden önce uygulama durumunu kaydetme

Kimlik doğrulama işlemi sırasında, tarayıcı IP'ye yeniden yönlendirilmeden önce uygulama durumunu kaydetmek istediğiniz durumlar vardır. Durum kapsayıcısı kullanırken ve kimlik doğrulaması başarılı olduktan sonra durumu geri yüklemek istediğinizde bu durum söz konusu olabilir. Uygulamaya özgü durumu veya başvuruyu korumak ve kimlik doğrulama işlemi başarıyla tamamlandıktan sonra bu durumu geri yüklemek için özel bir kimlik doğrulama durumu nesnesi kullanabilirsiniz. Aşağıdaki örnekte yaklaşımı gösterilmektedir.

Uygulamada, uygulamanın durum değerlerini tutacak özelliklere sahip bir durum kapsayıcısı sınıfı oluşturulur. Aşağıdaki örnekte kapsayıcı, varsayılan Blazor proje şablonununCounter bileşeninin (Counter.razor) sayaç değerini korumak için kullanılır. Kapsayıcıyı seri hale getirme ve seri durumdan çıkarma yöntemleri tabanlıdır System.Text.Json.

using System.Text.Json;

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

    public string GetStateForLocalStorage()
    {
        return JsonSerializer.Serialize(this);
    }

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

        CounterValue = deserializedState.CounterValue;
    }
}

Bileşen, Counter değeri bileşenin dışında tutmak currentCount için durum kapsayıcısını kullanır:

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

uygulamasından RemoteAuthenticationStatebir ApplicationAuthenticationState oluşturun. Id Yerel olarak depolanan durum için tanımlayıcı işlevi görecek bir özellik sağlayın.

ApplicationAuthenticationState.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public class ApplicationAuthenticationState : RemoteAuthenticationState
{
    public string? Id { get; set; }
}
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

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

Bileşen (Authentication.razor) yerel oturum depolamasını kullanarak serileştirme ve seri durumdan çıkarma yöntemleriyle StateContainerGetStateForLocalStorage uygulamanın durumunu kaydeder ve geri yükler ve SetStateFromLocalStorage:Authentication

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

Bu örnekte kimlik doğrulaması için Microsoft Entra (ME-ID) kullanılır. Program dosyasında:

  • ApplicationAuthenticationState, Microsoft Kimlik Doğrulama Kitaplığı (MSAL) RemoteAuthenticationState türü olarak yapılandırılır.
  • Durum kapsayıcısı hizmet kapsayıcısında kayıtlıdır.
builder.Services.AddMsalAuthentication<ApplicationAuthenticationState>(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});

builder.Services.AddSingleton<StateContainer>();

Uygulama yollarını özelleştirme

Varsayılan olarak, Microsoft.AspNetCore.Components.WebAssembly.Authentication kitaplık farklı kimlik doğrulama durumlarını temsil etmek için aşağıdaki tabloda gösterilen yolları kullanır.

Rota Purpose
authentication/login Oturum açma işlemini tetikler.
authentication/login-callback Herhangi bir oturum açma işleminin sonucunu işler.
authentication/login-failed Oturum açma işlemi bir nedenle başarısız olduğunda hata iletilerini görüntüler.
authentication/logout Oturumu kapatma işlemini tetikler.
authentication/logout-callback Oturumu kapatma işleminin sonucunu işler.
authentication/logout-failed Oturum kapatma işlemi bir nedenle başarısız olduğunda hata iletilerini görüntüler.
authentication/logged-out Kullanıcının oturumunu başarıyla kapattığını gösterir.
authentication/profile Kullanıcı profilini düzenlemek için bir işlem tetikler.
authentication/register Yeni bir kullanıcı kaydetmek için bir işlemi tetikler.

Önceki tabloda gösterilen yollar aracılığıyla RemoteAuthenticationOptions<TRemoteAuthenticationProviderOptions>.AuthenticationPathsyapılandırılabilir. Özel yollar sağlamak için seçenekleri ayarlarken, uygulamanın her yolu işleyen bir yolu olduğunu onaylayın.

Aşağıdaki örnekte, tüm yollara ön ek eklenmiştir /security.

Authentication bileşen (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; }
}

Program dosyasında:

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

Gereksinim tamamen farklı yolları çağırıyorsa, yolları daha önce açıklandığı gibi ayarlayın ve açık bir eylem parametresiyle işleyin RemoteAuthenticatorView :

@page "/register"

<RemoteAuthenticatorView Action="RemoteAuthenticationActions.Register" />

Bunu yapmayı seçerseniz kullanıcı arabirimini farklı sayfalara bölmenize izin verilir.

Kimlik doğrulama kullanıcı arabirimini özelleştirme

RemoteAuthenticatorView her kimlik doğrulama durumu için varsayılan bir kullanıcı arabirimi parçaları kümesi içerir. Her durum özel RenderFragmentbir geçirilerek özelleştirilebilir. İlk oturum açma işlemi sırasında görüntülenen metni özelleştirmek için aşağıdaki gibi değiştirebilirsiniz RemoteAuthenticatorView .

Authentication bileşen (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; }
}

aşağıdaki RemoteAuthenticatorView tabloda gösterilen kimlik doğrulama yolu başına kullanılabilecek bir parçaya sahiptir.

Rota Parça
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>

Kullanıcıyı özelleştirme

Uygulamaya bağlı kullanıcılar özelleştirilebilir.

Kullanıcıyı yük talebiyle özelleştirme

Aşağıdaki örnekte, uygulamanın kimliği doğrulanmış kullanıcıları kullanıcının kimlik doğrulama yöntemlerinin her biri için bir amr talep alır. Talep, amr belirtecin sahibinin Microsoft Identity Platform v1.0 yük taleplerinde kimliğinin nasıl doğrulandığını tanımlar. Örnek, tabanlı RemoteUserAccountbir özel kullanıcı hesabı sınıfı kullanır.

sınıfını genişleten RemoteUserAccount bir sınıf oluşturun. Aşağıdaki örnek, özelliği kullanıcının ON özellik değerleri dizisine amrJSayarlarAuthenticationMethod. AuthenticationMethod , kullanıcının kimliği doğrulandığında çerçeve tarafından otomatik olarak doldurulur.

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

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("amr")]
    public string[]? AuthenticationMethod { get; set; }
}
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

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

kullanıcının içinde CustomUserAccount.AuthenticationMethoddepolanan kimlik doğrulama yöntemlerinden talep oluşturmak için genişleten AccountClaimsPrincipalFactory<TAccount> bir fabrika oluşturun:

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

public class CustomAccountFactory 
    : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    public CustomAccountFactory(NavigationManager navigation, 
        IAccessTokenProviderAccessor accessor) : base(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;
    }
}
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;

public class CustomAccountFactory 
    : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    public CustomAccountFactory(NavigationManager navigation, 
        IAccessTokenProviderAccessor accessor) : base(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;

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

        return initialUser;
    }
}

CustomAccountFactory kullanılan kimlik doğrulama sağlayıcısı için öğesini kaydedin. Aşağıdaki kayıtlardan herhangi biri geçerlidir:

  • 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>();
    

Özel kullanıcı hesabı sınıfına sahip ME-ID güvenlik grupları ve rolleri

ME-ID güvenlik grupları ve ME-ID Yönetici istrator Rolleri ve özel kullanıcı hesabı sınıfıyla çalışan ek bir örnek için bkz. Microsoft Entra Id grupları ve rolleri ile ASP.NET CoreBlazor WebAssembly.

Kimlik doğrulaması ile önceden giriş

Kimlik doğrulaması ve yetkilendirme gerektiren ön kayıt içeriği şu anda desteklenmemektedir. Güvenlik uygulaması konularından birinde yer alan Blazor WebAssembly yönergeleri takip ettikten sonra aşağıdaki yönergeleri kullanarak şu adımları izleyin:

  • Yetkilendirme gerektirmeyen prerenders yolları.
  • Yetkilendirmenin gerekli olduğu yolları önceden oluşturmaz.

Client Projenin Program dosyası için ortak hizmet kayıtlarını ayrı bir yönteme ekleyin (örneğin, projede Client bir ConfigureCommonServices yöntem oluşturun). Yaygın hizmetler, geliştiricinin hem istemci hem de sunucu projeleri tarafından kullanılmak üzere kaydolan hizmetlerdir.

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

Program dosyasında:

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

builder.Services.AddScoped( ... );

ConfigureCommonServices(builder.Services);

await builder.Build().RunAsync();

Server Projenin Program dosyasında aşağıdaki ek hizmetleri kaydedin ve öğesini çağırınConfigureCommonServices:

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

Projenin yönteminde Server aşağıdaki ek hizmetleri kaydedin ve öğesini çağırınConfigureCommonServices:Startup.ConfigureServices

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

Çerçeve sunucusu kimlik doğrulama sağlayıcısı ( ) hakkında Blazor daha fazla bilgi için bkz. ASP.NET Çekirdek Blazor kimlik doğrulaması ve yetkilendirme.ServerAuthenticationStateProvider

Server Projenin dosyasında Etiket Yardımcısı'nı Pages/_Host.cshtmlComponent (<component ... />) aşağıdakilerle değiştirin:

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

Yukarıdaki örnekte:

  • Yer tutucu {CLIENT APP ASSEMBLY NAME} , istemci uygulamasının derleme adıdır (örneğin BlazorSample.Client).
  • Yol kesimi için /authentication koşullu denetim:
    • Kimlik doğrulama yolları için ön kayıttan (render-mode="WebAssembly") kaçınıyor.
    • Kimlik doğrulaması olmayan yollar için prerenders (render-mode="WebAssemblyPrerendered").

Barındırılan uygulamalar ve üçüncü taraf oturum açma sağlayıcıları için seçenekler

Barındırılan Blazor WebAssembly bir uygulamanın kimliğini doğrulamak ve üçüncü taraf sağlayıcıyla yetkilendirmek için kullanıcının kimliğini doğrulamak için çeşitli seçenekler vardır. Hangisini seçtiğiniz senaryonuza bağlıdır.

Daha fazla bilgi için, bkz. ASP.NET Core'da dış sağlayıcılardan gelen ek talepleri ve belirteçleri kalıcı hale getirme.

Yalnızca korumalı üçüncü taraf API'leri çağırmak için kullanıcıların kimliğini doğrulama

Üçüncü taraf API sağlayıcısında istemci tarafı OAuth akışıyla kullanıcının kimliğini doğrula:

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

Bu senaryoda:

  • Uygulamayı barındıran sunucu bir rol oynamaz.
  • Sunucudaki API'ler korunamaz.
  • Uygulama yalnızca korumalı üçüncü taraf API'leri çağırabilir.

Üçüncü taraf sağlayıcıyla kullanıcıların kimliğini doğrulama ve konak sunucusunda ve üçüncü taraf üzerinde korumalı API'leri çağırma

Üçüncü taraf oturum açma sağlayıcısıyla yapılandırın Identity . Üçüncü taraf API erişimi için gereken belirteçleri alın ve depolayın.

Kullanıcı oturum açtığında, Identity kimlik doğrulama işleminin bir parçası olarak erişim ve yenileme belirteçlerini toplar. Bu noktada, üçüncü taraf API'lere API çağrıları yapmak için kullanılabilecek birkaç yaklaşım vardır.

Üçüncü taraf erişim belirtecini almak için sunucu erişim belirteci kullanma

Sunucu API'sinin uç noktasından üçüncü taraf erişim belirtecini almak için sunucuda oluşturulan erişim belirtecini kullanın. Buradan, üçüncü taraf API kaynaklarını doğrudan istemciden Identity çağırmak için üçüncü taraf erişim belirtecini kullanın.

Bu yaklaşımı önermiyoruz. Bu yaklaşım, üçüncü taraf erişim belirtecinin genel istemci için oluşturulmuş gibi ele alındığını gerektirir. OAuth terimlerinde, gizli dizileri güvenli bir şekilde depolamaya güvenilemediği ve erişim belirteci gizli bir istemci için üretildiği için genel uygulamanın gizli dizisi yoktur. Gizli istemci, gizli dizisi olan ve gizli dizileri güvenli bir şekilde depolayabildiği varsayılan bir istemcidir.

  • Üçüncü taraf erişim belirtecine, üçüncü tarafın daha güvenilir bir istemci için belirteci yayması temelinde hassas işlemler gerçekleştirmek için ek kapsamlar verilebilir.
  • Benzer şekilde, yenileme belirteçleri güvenilir olmayan bir istemciye verilmemelidir, çünkü bunu yapmak istemciye başka kısıtlamalar getirilmediği sürece sınırsız erişim verir.

Üçüncü taraf API'leri çağırmak için istemciden sunucu API'sine API çağrıları yapma

İstemciden sunucu API'sine bir API çağrısı yapın. Sunucudan, üçüncü taraf API kaynağı için erişim belirtecini alın ve gereken çağrıyı yapın.

Bu yaklaşımı öneririz. Bu yaklaşım, bir üçüncü taraf API'yi çağırmak için sunucuda fazladan bir ağ atlama gerektirir ancak sonuçta daha güvenli bir deneyim elde edersiniz:

  • Sunucu yenileme belirteçlerini depolayabilir ve uygulamanın üçüncü taraf kaynaklara erişimini kaybetmediğinden emin olabilir.
  • Uygulama, daha hassas izinler içerebilecek sunucudan erişim belirteçlerini sızdıramaz.

OpenID Bağlan (OIDC) v2.0 uç noktalarını kullanma

Kimlik doğrulama kitaplığı ve Blazor proje şablonları OpenID Bağlan (OIDC) v1.0 uç noktalarını kullanır. v2.0 uç noktasını kullanmak için JWT Taşıyıcı JwtBearerOptions.Authority seçeneğini yapılandırın. Aşağıdaki örnekte, ME-ID özelliğine Authority bir v2.0 kesim eklenerek v2.0 için yapılandırılır:

using Microsoft.AspNetCore.Authentication.JwtBearer;

...

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

Alternatif olarak, ayar uygulama ayarları (appsettings.json) dosyasında yapılabilir:

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

Bir segmenti yetkiliye eklemek, uygulamanın OIDC sağlayıcısı için uygun değilse (me kimliği olmayan sağlayıcılarda olduğu gibi) özelliği doğrudan ayarlayın Authority . özelliğini JwtBearerOptions veya uygulama ayarları dosyasında (appsettings.json) anahtarıyla Authority ayarlayın.

Kimlik belirtecindeki taleplerin listesi v2.0 uç noktaları için değişir. Değişikliklerle ilgili Microsoft belgeleri kullanımdan kaldırılmıştır, ancak kimlik belirtecindeki taleplere ilişkin yönergeler kimlik belirteci talep başvurusunda sağlanır.

Bileşenlerde gRPC'yi yapılandırma ve kullanma

Bir Blazor WebAssembly uygulamayı ASP.NET Core gRPC çerçevesini kullanacak şekilde yapılandırmak için:

Not

Ön kayıt Web Apps'te Blazor varsayılan olarak etkindir, bu nedenle önce sunucudan sonra istemciden bileşen işlemeyi hesaba eklemelisiniz. Yeniden kullanılabilmesi için önceden oluşturulmuş tüm durumların istemciye akması gerekir. Daha fazla bilgi için bkz . Prerender ASP.NET Core Razor bileşenleri.

Not

Ön kayıt, barındırılan Blazor WebAssembly uygulamalarda varsayılan olarak etkindir, bu nedenle önce sunucudan sonra istemciden bileşen işlemeyi hesaba aktarmanız gerekir. Yeniden kullanılabilmesi için önceden oluşturulmuş tüm durumların istemciye akması gerekir. Daha fazla bilgi için bkz . Prerender ve ASP.NET Core Razor bileşenlerini tümleştirme.

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

İstemci uygulamasındaki bir bileşen gRPC istemcisini (Grpc.razor) kullanarak gRPC çağrıları yapabilir:

@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();
        }
    }
}

özelliğini kullanmak Status.DebugException için 2.30.0 veya sonraki bir sürümü kullanın Grpc.Net.Client .

Daha fazla bilgi için bkz . ASP.NET Core gRPC uygulamalarında gRPC-Web.

AuthenticationService Uygulamayı değiştirme

Aşağıdaki alt bölümler, nasıl değiştirilmeyi açıklanmaktadır:

  • Herhangi bir JavaScript AuthenticationService uygulaması.
  • JavaScript için Microsoft Kimlik Doğrulama Kitaplığı (MSAL.js ).

Herhangi bir JavaScript AuthenticationService uygulamasını değiştirme

Özel kimlik doğrulama ayrıntılarınızı işlemek için bir JavaScript kitaplığı oluşturun.

Uyarı

Bu bölümdeki kılavuz, varsayılan RemoteAuthenticationService<TRemoteAuthenticationState,TAccount,TProviderOptions>öğesinin uygulama ayrıntılarıdır. Bu bölümdeki TypeScript kodu özellikle .NET 7'deki ASP.NET Core için geçerlidir ve ASP.NET Core'un gelecek sürümlerinde bildirimde bulunmadan değiştirilebilir.

// .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 };
};

Özgün <script> etiketi kaldırıp özel kitaplığı yükleyen bir <script> etiket ekleyerek kitaplığı içeri aktarabilirsiniz. Aşağıdaki örnek, varsayılan <script> etiketi klasörden adlı CustomAuthenticationService.jswwwroot/js bir kitaplığı yükleyen bir etiketle değiştirmeyi gösterir.

wwwroot/index.html Kapatma </body> etiketinin Blazor içindeki betikten (_framework/blazor.webassembly.js) önce:

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

Daha fazla bilgi için GitHub deposundaki bölümüne bakınAuthenticationService.ts.dotnet/aspnetcore

Not

.NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

JavaScript için Microsoft Kimlik Doğrulama Kitaplığı'nı değiştirme (MSAL.js)

Bir uygulama JavaScript için Microsoft Kimlik Doğrulama Kitaplığı'nın (MSAL.js)özel bir sürümünü gerektiriyorsa aşağıdaki adımları gerçekleştirin:

  1. Sistemin en son geliştirici .NET SDK'sı olduğunu onaylayın veya .NET Core SDK'sından en son geliştirici SDK'sını alın ve yükleyin: Yükleyiciler ve İkili Dosyalar. Bu senaryo için iç NuGet akışlarının yapılandırılması gerekli değildir.
  2. Kaynaktan dotnet/aspnetcoreASP.NET Core Oluşturma konusundaki belgeleri izleyerek GitHub deposunu geliştirme için ayarlayın. Çatal oluşturun ve GitHub deposunun ZIP arşivini dotnet/aspnetcore kopyalayın veya indirin.
  3. src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json dosyasını açın ve istenen sürümünü @azure/msal-browserayarlayın. Yayımlanan sürümlerin listesi için npm web sitesini ziyaret edin @azure/msal-browser ve Sürümler sekmesini seçin.
  4. Authentication.Msal Komutu bir komut kabuğunda src/Components/WebAssembly/Authentication.Msal/src komutuyla yarn build klasöründe projeyi oluşturun.
  5. Uygulama sıkıştırılmış varlıklar (Brotli/Gzip) kullanıyorsa dosyayı sıkıştırınInterop/dist/Release/AuthenticationService.js.
  6. AuthenticationService.js Oluşturulursa, dosyanın dosyasını ve sıkıştırılmış sürümlerini (.br.gz/) klasörden Interop/dist/Release uygulamanın yayımlanan varlıklarındaki uygulamanın publish/wwwroot/_content/Microsoft.Authentication.WebAssembly.Msal klasörüne kopyalayın.

Özel sağlayıcı seçeneklerini geçirme

Verileri temel alınan JavaScript kitaplığına geçirmek için bir sınıf tanımlayın.

Önemli

ON ile seri hale getirildiğinde sınıfın yapısı kitaplığın JSbeklediğiyle System.Text.Jsoneşleşmelidir.

Aşağıdaki örnekte, varsayımsal ProviderOptions bir özel sağlayıcı kitaplığının beklentileriyle eşleşen özniteliklere sahip JsonPropertyName bir sınıf gösterilmektedir:

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; } = 
        new List<string> { "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; }
}
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; } = 
        new List<string> { "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; }
}

DI sistemindeki sağlayıcı seçeneklerini kaydedin ve uygun değerleri yapılandırın:

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

Yukarıdaki örnek, normal dize değişmez değerleriyle yeniden yönlendirme URI'lerini ayarlar. Aşağıdaki alternatifler kullanılabilir:

  • TryCreate kullanarak IWebAssemblyHostEnvironment.BaseAddress:

    Uri.TryCreate(
        $"{builder.HostEnvironment.BaseAddress}authentication/login-callback", 
        UriKind.Absolute, out var redirectUri);
    options.RedirectUri = redirectUri;
    
  • Konak oluşturucu yapılandırması:

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

    wwwroot/appsettings.json:

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

Ek kaynaklar