Bagikan melalui


Menggunakan Graph API dengan ASP.NET Core Blazor WebAssembly

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Peringatan

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Artikel ini menjelaskan cara menggunakan Microsoft Graph di Blazor WebAssembly aplikasi, yang memungkinkan aplikasi mengakses sumber daya Microsoft Cloud.

Dua pendekatan tercakup:

  • Graph SDK: Microsoft Graph SDK menyederhanakan pembuatan aplikasi berkualitas tinggi, efisien, dan tangguh yang mengakses Microsoft Graph. Pilih tombol Graph SDK di bagian atas artikel ini untuk mengadopsi pendekatan ini.

  • Bernama HttpClient dengan Graph API: Bernama HttpClientdapat mengeluarkan permintaan Microsoft Graph API langsung ke Microsoft Graph. Pilih tombol Bernama HttpClient dengan Graph API di bagian atas artikel ini untuk mengadopsi pendekatan ini.

Panduan dalam artikel ini tidak dimaksudkan untuk mengganti dokumentasi Microsoft Graph dan panduan keamanan Azure dalam kumpulan dokumentasi Microsoft lainnya. Menilai panduan keamanan di bagian Sumber daya tambahan di artikel ini sebelum menerapkan Microsoft Graph di lingkungan produksi. Ikuti praktik terbaik Microsoft untuk membatasi kerentanan aplikasi Anda.

Pendekatan tambahan untuk bekerja dengan Microsoft Graph dan Blazor WebAssembly disediakan oleh sampel Microsoft Graph dan Azure berikut:

Untuk memberikan umpan balik tentang salah satu dari dua sampel sebelumnya, buka masalah pada repositori GitHub sampel. Jika Anda membuka masalah untuk sampel Azure, berikan tautan ke sampel di komentar pembukaan Anda karena repositori sampel Azure (Azure-Samples) berisi banyak sampel. Jelaskan masalah secara rinci dan sertakan kode sampel sesuai kebutuhan. Tempatkan aplikasi minimal ke GitHub yang mereproduksi masalah atau kesalahan. Pastikan untuk menghapus data konfigurasi akun Azure dari sampel sebelum Anda menerapkannya ke repositori publik.

Untuk memberikan umpan balik atau mencari bantuan dengan artikel ini atau ASP.NET Core, lihat dasar-dasar ASP.NET CoreBlazor.

Penting

Skenario yang dijelaskan dalam artikel ini berlaku untuk menggunakan Microsoft Entra (ME-ID) sebagai identity penyedia, bukan AAD B2C. Menggunakan Microsoft Graph dengan aplikasi sisi Blazor WebAssembly klien dan penyedia AAD B2C identity saat ini tidak didukung karena aplikasi akan memerlukan rahasia klien, yang tidak dapat diamankan di aplikasi sisi Blazor klien. Untuk aplikasi mandiri Blazor WebAssembly AAD B2C menggunakan Graph API, buat API server backend (web) untuk mengakses Graph API atas nama pengguna. Aplikasi sisi klien mengautentikasi dan mengotorisasi pengguna untuk memanggil API web untuk mengakses Microsoft Graph dengan aman dan mengembalikan data ke aplikasi sisi Blazor klien dari API web berbasis server Anda. Rahasia klien dikelola dengan aman di API web berbasis server, bukan di Blazor aplikasi pada klien. Jangan pernah menyimpan rahasia klien di aplikasi sisi Blazor klien.

Menggunakan aplikasi yang dihosting Blazor WebAssembly didukung, di mana Server aplikasi menggunakan Graph SDK/API untuk menyediakan data Grafik ke Client aplikasi melalui API web. Untuk informasi selengkapnya, lihat bagian Solusi yang dihosting Blazor WebAssembly di artikel ini.

Contoh dalam artikel ini memanfaatkan fitur .NET/C# baru. Saat menggunakan contoh dengan .NET 7 atau yang lebih lama, modifikasi kecil diperlukan. Namun, contoh teks dan kode yang berkaitan dengan berinteraksi dengan Microsoft Graph sama untuk semua versi ASP.NET Core.

Panduan berikut berlaku untuk Microsoft Graph v5.

Microsoft Graph SDK untuk digunakan dalam Blazor aplikasi disebut Microsoft Graph .NET Client Library.

Contoh Graph SDK memerlukan referensi paket berikut di aplikasi mandiri Blazor WebAssembly . Dua paket pertama sudah dirujuk jika aplikasi telah diaktifkan untuk autentikasi MSAL, misalnya saat membuat aplikasi dengan mengikuti panduan dalam Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan MICROSOFT Entra ID.

Contoh Graph SDK memerlukan referensi paket berikut di aplikasi mandiri Blazor WebAssembly atau Client aplikasi solusi yang dihosting Blazor WebAssembly . Dua paket pertama sudah dirujuk jika aplikasi telah diaktifkan untuk autentikasi MSAL, misalnya saat membuat aplikasi dengan mengikuti panduan dalam Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan MICROSOFT Entra ID.

Catatan

Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.

Dalam portal Azure, berikan izin yang didelegasikan (cakupan)† untuk data Microsoft Graph yang harus dapat diakses aplikasi atas nama pengguna. Untuk contoh dalam artikel ini, pendaftaran aplikasi harus menyertakan izin yang didelegasikan untuk membaca data pengguna (Microsoft.Graph>User.Read cakupan dalam izin API, Jenis: Didelegasikan). Cakupan memungkinkan User.Read pengguna untuk masuk ke aplikasi dan memungkinkan aplikasi membaca profil dan informasi perusahaan pengguna yang masuk. Untuk informasi selengkapnya, lihat Gambaran Umum izin dan persetujuan di platform Microsoft identity dan Gambaran Umum izin Microsoft Graph.

†Permissions dan cakupan berarti hal yang sama dan digunakan secara bergantian dalam dokumentasi keamanan dan portal Azure. Kecuali teks mengacu pada portal Azure, artikel ini menggunakan cakupan/ saat merujuk ke izin Grafik.

Cakupan tidak peka huruf besar/kecil, jadi User.Read sama user.readdengan . Jangan ragu untuk menggunakan salah satu format, tetapi kami merekomendasikan pilihan yang konsisten di seluruh kode aplikasi.

Setelah menambahkan cakupan Microsoft Graph API ke pendaftaran aplikasi di portal Azure, tambahkan konfigurasi pengaturan aplikasi berikut ke wwwroot/appsettings.json file di aplikasi, yang mencakup URL dasar Grafik dengan versi dan cakupan Microsoft Graph. Dalam contoh berikut, User.Read cakupan ditentukan untuk contoh di bagian selanjutnya dari artikel ini. Cakupan tidak peka huruf besar/kecil.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com",
  "Version": "{VERSION}",
  "Scopes": [
    "user.read"
  ]
}

Dalam contoh sebelumnya, {VERSION} tempat penampung adalah versi Microsoft Graph API (misalnya: v1.0).

Berikut ini adalah contoh file konfigurasi lengkap wwwroot/appsettings.json untuk aplikasi yang menggunakan ME-ID sebagai penyedianya identity , di mana membaca data pengguna (user.read cakupan) ditentukan untuk Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com",
    "Version": "v1.0",
    "Scopes": [
      "user.read"
    ]
  }
}

Dalam contoh sebelumnya, {TENANT ID} tempat penampung adalah ID Direktori (penyewa), dan {CLIENT ID} tempat penampung adalah ID Aplikasi (klien). Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Tambahkan kelas berikut GraphClientExtensions ke aplikasi mandiri. Cakupan disediakan untuk Scopes properti dari AccessTokenRequestOptions dalam AuthenticateRequestAsync metode .

Tambahkan kelas berikut GraphClientExtensions ke aplikasi atau Client aplikasi mandiri dari solusi yang dihostingBlazor WebAssembly. Cakupan disediakan untuk Scopes properti dari AccessTokenRequestOptions dalam AuthenticateRequestAsync metode .

Saat token akses tidak diperoleh, kode berikut tidak mengatur header otorisasi Pembawa untuk permintaan Grafik.

GraphClientExtensions.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Authentication.WebAssembly.Msal.Models;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Authentication;
using IAccessTokenProvider = 
    Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider;

namespace BlazorSample;

internal static class GraphClientExtensions
{
    public static IServiceCollection AddGraphClient(
            this IServiceCollection services, string? baseUrl, List<string>? scopes)
    {
        if (string.IsNullOrEmpty(baseUrl) || scopes?.Count == 0)
        {
            return services;
        }

        services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
            options =>
            {
                scopes?.ForEach((scope) =>
                {
                    options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
                });
            });

        services.AddScoped<IAuthenticationProvider, GraphAuthenticationProvider>();

        services.AddScoped(sp =>
        {
            return new GraphServiceClient(
                new HttpClient(),
                sp.GetRequiredService<IAuthenticationProvider>(),
                baseUrl);
        });

        return services;
    }

    private class GraphAuthenticationProvider(IAccessTokenProvider tokenProvider, 
        IConfiguration config) : IAuthenticationProvider
    {
        private readonly IConfiguration config = config;

        public IAccessTokenProvider TokenProvider { get; } = tokenProvider;

        public async Task AuthenticateRequestAsync(RequestInformation request, 
            Dictionary<string, object>? additionalAuthenticationContext = null, 
            CancellationToken cancellationToken = default)
        {
            var result = await TokenProvider.RequestAccessToken(
                new AccessTokenRequestOptions()
                {
                    Scopes = 
                        config.GetSection("MicrosoftGraph:Scopes").Get<string[]>() ??
                        [ "user.read" ]
                });

            if (result.TryGetToken(out var token))
            {
                request.Headers.Add("Authorization", 
                    $"{CoreConstants.Headers.Bearer} {token.Value}");
            }
        }
    }
}

Penting

Lihat bagian DefaultAccessTokenScopes versus AdditionalScopesToConsent untuk penjelasan tentang mengapa kode sebelumnya menggunakan DefaultAccessTokenScopes untuk menambahkan cakupan daripada AdditionalScopesToConsent.

Program Dalam file, tambahkan layanan dan konfigurasi klien Graph dengan AddGraphClient metode ekstensi. Kode berikut default ke alamat dasar dan User.Read cakupan Microsoft Graph Versi 1.0 jika pengaturan ini tidak ditemukan dalam file pengaturan aplikasi:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Memanggil Graph API dari komponen menggunakan Graph SDK

Komponen berikut UserData menggunakan yang disuntikkan GraphServiceClient untuk mendapatkan data profil ME-ID pengguna dan menampilkan nomor ponsel mereka.

Untuk pengguna uji apa pun yang Anda buat di ME-ID, pastikan Anda memberi nomor ponsel pada profil ME-ID pengguna di portal Azure.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Graph
@attribute [Authorize]
@inject GraphServiceClient Client

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(user?.MobilePhone))
{
    <p>Mobile Phone: @user.MobilePhone</p>
}

@code {
    private Microsoft.Graph.Models.User? user;

    protected override async Task OnInitializedAsync()
    {
        user = await Client.Me.GetAsync();
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

Tip

Untuk menambahkan pengguna ke aplikasi, lihat bagian Menetapkan pengguna ke pendaftaran aplikasi dengan atau tanpa peran aplikasi.

Saat menguji dengan Graph SDK secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Menyesuaikan klaim pengguna menggunakan Graph SDK

Dalam contoh berikut, aplikasi membuat nomor ponsel dan klaim lokasi kantor untuk pengguna dari data profil pengguna ME-ID mereka. Aplikasi harus memiliki cakupan Graph API yang User.Read dikonfigurasi dalam ME-ID. Setiap pengguna uji untuk skenario ini harus memiliki nomor ponsel dan lokasi kantor di profil ME-ID mereka, yang dapat ditambahkan melalui portal Azure.

Di pabrik akun pengguna kustom berikut:

  • ILogger (logger) disertakan untuk kenyamanan jika Anda ingin mencatat informasi atau kesalahan dalam metode .CreateUserAsync
  • AccessTokenNotAvailableException Jika dilemparkan, pengguna dialihkan ke identity penyedia untuk masuk ke akun mereka. Tindakan tambahan atau berbeda dapat diambil saat meminta token akses gagal. Misalnya, aplikasi dapat mencatat AccessTokenNotAvailableException dan membuat tiket dukungan untuk penyelidikan lebih lanjut.
  • Kerangka kerja mewakili RemoteUserAccount akun pengguna. Jika aplikasi memerlukan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom Anda dalam RemoteUserAccount kode berikut.

CustomAccountFactory.cs:

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

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider, ILogger<CustomAccountFactory> logger,
        IConfiguration config) 
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;
    private readonly string? baseUrl = string.Join("/",
        config.GetSection("MicrosoftGraph")["BaseUrl"] ?? 
            "https://graph.microsoft.com",
        config.GetSection("MicrosoftGraph")["Version"] ??
            "v1.0");

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null && !string.IsNullOrEmpty(baseUrl))
            {
                try
                {
                    var client = new GraphServiceClient(
                        new HttpClient(),
                        serviceProvider
                            .GetRequiredService<IAuthenticationProvider>(),
                        baseUrl);

                    var user = await client.Me.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Konfigurasikan autentikasi MSAL untuk menggunakan pabrik akun pengguna kustom.

Konfirmasikan bahwa Program file menggunakan Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace layanan:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Contoh di bagian ini dibangun berdasarkan pendekatan membaca URL dasar dengan versi dan cakupan dari konfigurasi aplikasi melalui MicrosoftGraph bagian dalam wwwroot/appsettings.json file. Baris berikut harus sudah ada dalam Program file dari mengikuti panduan sebelumnya dalam artikel ini:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Program Dalam file, temukan panggilan ke AddMsalAuthentication metode ekstensi. Perbarui kode ke yang berikut, yang menyertakan panggilan ke AddAccountClaimsPrincipalFactory yang menambahkan pabrik utama klaim akun dengan CustomAccountFactory.

Jika aplikasi menggunakan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom untuk RemoteUserAccount dalam kode berikut.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
        CustomAccountFactory>();

Anda dapat menggunakan komponen berikut UserClaims untuk mempelajari klaim pengguna setelah pengguna mengautentikasi dengan ME-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Saat menguji dengan Graph SDK secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Panduan berikut berlaku untuk Microsoft Graph v4. Jika Anda meningkatkan aplikasi dari SDK v4 ke v5, lihat panduan perubahan dan peningkatan Microsoft Graph .NET SDK v5.

Microsoft Graph SDK untuk digunakan dalam Blazor aplikasi disebut Microsoft Graph .NET Client Library.

Contoh Graph SDK memerlukan referensi paket berikut di aplikasi mandiri Blazor WebAssembly . Dua paket pertama sudah dirujuk jika aplikasi telah diaktifkan untuk autentikasi MSAL, misalnya saat membuat aplikasi dengan mengikuti panduan dalam Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan MICROSOFT Entra ID.

Contoh Graph SDK memerlukan referensi paket berikut di aplikasi mandiri Blazor WebAssembly atau Client aplikasi solusi yang dihosting Blazor WebAssembly . Dua paket pertama sudah dirujuk jika aplikasi telah diaktifkan untuk autentikasi MSAL, misalnya saat membuat aplikasi dengan mengikuti panduan dalam Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan MICROSOFT Entra ID.

Catatan

Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.

Dalam portal Azure, berikan izin yang didelegasikan (cakupan)† untuk data Microsoft Graph yang harus dapat diakses aplikasi atas nama pengguna. Untuk contoh dalam artikel ini, pendaftaran aplikasi harus menyertakan izin yang didelegasikan untuk membaca data pengguna (Microsoft.Graph>User.Read cakupan dalam izin API, Jenis: Didelegasikan). Cakupan memungkinkan User.Read pengguna untuk masuk ke aplikasi dan memungkinkan aplikasi membaca profil dan informasi perusahaan pengguna yang masuk. Untuk informasi selengkapnya, lihat Gambaran Umum izin dan persetujuan di platform Microsoft identity dan Gambaran Umum izin Microsoft Graph.

†Permissions dan cakupan berarti hal yang sama dan digunakan secara bergantian dalam dokumentasi keamanan dan portal Azure. Kecuali teks mengacu pada portal Azure, artikel ini menggunakan cakupan/ saat merujuk ke izin Grafik.

Cakupan tidak peka huruf besar/kecil, jadi User.Read sama user.readdengan . Jangan ragu untuk menggunakan salah satu format, tetapi kami merekomendasikan pilihan yang konsisten di seluruh kode aplikasi.

Setelah menambahkan cakupan Microsoft Graph API ke pendaftaran aplikasi di portal Azure, tambahkan konfigurasi pengaturan aplikasi berikut ke wwwroot/appsettings.json file di aplikasi, yang mencakup URL dasar Grafik dengan versi dan cakupan Microsoft Graph. Dalam contoh berikut, User.Read cakupan ditentukan untuk contoh di bagian selanjutnya dari artikel ini. Cakupan tidak peka huruf besar/kecil.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com",
  "Version": "{VERSION}",
  "Scopes": [
    "user.read"
  ]
}

Dalam contoh sebelumnya, {VERSION} tempat penampung adalah versi Microsoft Graph API (misalnya: v1.0).

Berikut ini adalah contoh file konfigurasi lengkap wwwroot/appsettings.json untuk aplikasi yang menggunakan ME-ID sebagai penyedianya identity , di mana membaca data pengguna (user.read cakupan) ditentukan untuk Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com",
    "Version": "v1.0",
    "Scopes": [
      "user.read"
    ]
  }
}

Dalam contoh sebelumnya, {TENANT ID} tempat penampung adalah ID Direktori (penyewa), dan {CLIENT ID} tempat penampung adalah ID Aplikasi (klien). Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Tambahkan kelas berikut GraphClientExtensions ke aplikasi mandiri. Cakupan disediakan untuk Scopes properti dari AccessTokenRequestOptions dalam AuthenticateRequestAsync metode . IHttpProvider.OverallTimeout diperluas dari nilai default 100 detik hingga 300 detik untuk memberikan lebih banyak HttpClient waktu untuk menerima respons dari Microsoft Graph.

Tambahkan kelas berikut GraphClientExtensions ke aplikasi atau Client aplikasi mandiri dari solusi yang dihostingBlazor WebAssembly. Cakupan disediakan untuk Scopes properti dari AccessTokenRequestOptions dalam AuthenticateRequestAsync metode . IHttpProvider.OverallTimeout diperluas dari nilai default 100 detik hingga 300 detik untuk memberikan lebih banyak HttpClient waktu untuk menerima respons dari Microsoft Graph.

Saat token akses tidak diperoleh, kode berikut tidak mengatur header otorisasi Pembawa untuk permintaan Grafik.

GraphClientExtensions.cs:

using System.Net.Http.Headers;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Authentication.WebAssembly.Msal.Models;
using Microsoft.Graph;

namespace BlazorSample;

internal static class GraphClientExtensions
{
    public static IServiceCollection AddGraphClient(
        this IServiceCollection services, string? baseUrl, List<string>? scopes)
    {
        if (string.IsNullOrEmpty(baseUrl) || scopes?.Count == 0)
        {
            return services;
        }

        services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
            options =>
            {
                scopes?.ForEach((scope) =>
                {
                    options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
                });
            });

        services.AddScoped<IAuthenticationProvider, GraphAuthenticationProvider>();

        services.AddScoped<IHttpProvider, HttpClientHttpProvider>(sp =>
            new HttpClientHttpProvider(new HttpClient()));

        services.AddScoped(sp =>
        {
            return new GraphServiceClient(
                baseUrl,
                sp.GetRequiredService<IAuthenticationProvider>(),
                sp.GetRequiredService<IHttpProvider>());
        });

        return services;
    }

    private class GraphAuthenticationProvider(IAccessTokenProvider tokenProvider, 
        IConfiguration config) : IAuthenticationProvider
    {
        private readonly IConfiguration config = config;

        public IAccessTokenProvider TokenProvider { get; } = tokenProvider;

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            var result = await TokenProvider.RequestAccessToken(
                new AccessTokenRequestOptions()
                { 
                    Scopes = config.GetSection("MicrosoftGraph:Scopes").Get<string[]>()
                });

            if (result.TryGetToken(out var token))
            {
                request.Headers.Authorization ??= new AuthenticationHeaderValue(
                    "Bearer", token.Value);
            }
        }
    }

    private class HttpClientHttpProvider(HttpClient client) : IHttpProvider
    {
        private readonly HttpClient client = client;

        public ISerializer Serializer { get; } = new Serializer();

        public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(300);

        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
        {
            return client.SendAsync(request);
        }

        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            HttpCompletionOption completionOption,
            CancellationToken cancellationToken)
        {
            return client.SendAsync(request, completionOption, cancellationToken);
        }

        public void Dispose()
        {
        }
    }
}

Penting

Lihat bagian DefaultAccessTokenScopes versus AdditionalScopesToConsent untuk penjelasan tentang mengapa kode sebelumnya menggunakan DefaultAccessTokenScopes untuk menambahkan cakupan daripada AdditionalScopesToConsent.

Program Dalam file, tambahkan layanan dan konfigurasi klien Graph dengan AddGraphClient metode ekstensi:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Memanggil Graph API dari komponen menggunakan Graph SDK

Komponen berikut UserData menggunakan yang disuntikkan GraphServiceClient untuk mendapatkan data profil ME-ID pengguna dan menampilkan nomor ponsel mereka. Untuk pengguna uji apa pun yang Anda buat di ME-ID, pastikan Anda memberi nomor ponsel pada profil ME-ID pengguna di portal Azure.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Graph
@attribute [Authorize]
@inject GraphServiceClient Client

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(user?.MobilePhone))
{
    <p>Mobile Phone: @user.MobilePhone</p>
}

@code {
    private Microsoft.Graph.User? user;

    protected override async Task OnInitializedAsync()
    {
        var request = Client.Me.Request();
        user = await request.GetAsync();
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

Tip

Untuk menambahkan pengguna ke aplikasi, lihat bagian Menetapkan pengguna ke pendaftaran aplikasi dengan atau tanpa peran aplikasi.

Saat menguji dengan Graph SDK secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Menyesuaikan klaim pengguna menggunakan Graph SDK

Dalam contoh berikut, aplikasi membuat nomor ponsel dan klaim lokasi kantor untuk pengguna dari data profil pengguna ME-ID mereka. Aplikasi harus memiliki cakupan Graph API yang User.Read dikonfigurasi dalam ME-ID. Setiap pengguna uji untuk skenario ini harus memiliki nomor ponsel dan lokasi kantor di profil ME-ID mereka, yang dapat ditambahkan melalui portal Azure.

Di pabrik akun pengguna kustom berikut:

  • ILogger (logger) disertakan untuk kenyamanan jika Anda ingin mencatat informasi atau kesalahan dalam metode .CreateUserAsync
  • AccessTokenNotAvailableException Jika dilemparkan, pengguna dialihkan ke identity penyedia untuk masuk ke akun mereka. Tindakan tambahan atau berbeda dapat diambil saat meminta token akses gagal. Misalnya, aplikasi dapat mencatat AccessTokenNotAvailableException dan membuat tiket dukungan untuk penyelidikan lebih lanjut.
  • Kerangka kerja mewakili RemoteUserAccount akun pengguna. Jika aplikasi memerlukan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom Anda dalam RemoteUserAccount kode berikut.

CustomAccountFactory.cs:

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

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor, 
        IServiceProvider serviceProvider, ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null && 
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                try
                {
                    var client = ActivatorUtilities
                        .CreateInstance<GraphServiceClient>(serviceProvider);
                    var request = client.Me.Request();
                    var user = await request.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Konfigurasikan autentikasi MSAL untuk menggunakan pabrik akun pengguna kustom.

Konfirmasikan bahwa Program file menggunakan Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace layanan:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Contoh di bagian ini dibangun berdasarkan pendekatan membaca URL dasar dengan versi dan cakupan dari konfigurasi aplikasi melalui MicrosoftGraph bagian dalam wwwroot/appsettings.json file. Baris berikut harus sudah ada dalam Program file dari mengikuti panduan sebelumnya dalam artikel ini:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Program Dalam file, temukan panggilan ke AddMsalAuthentication metode ekstensi. Perbarui kode ke yang berikut, yang menyertakan panggilan ke AddAccountClaimsPrincipalFactory yang menambahkan pabrik utama klaim akun dengan CustomAccountFactory.

Jika aplikasi menggunakan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom untuk RemoteUserAccount dalam kode berikut.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
        CustomAccountFactory>();

Anda dapat menggunakan komponen berikut UserClaims untuk mempelajari klaim pengguna setelah pengguna mengautentikasi dengan ME-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Saat menguji dengan Graph SDK secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Contoh berikut menggunakan panggilan bernama HttpClient untuk Graph API untuk mendapatkan nomor ponsel pengguna untuk memproses panggilan atau untuk menyesuaikan klaim pengguna untuk menyertakan klaim nomor ponsel dan klaim lokasi kantor.

Contoh memerlukan referensi paket untuk Microsoft.Extensions.Http aplikasi mandiri Blazor WebAssembly .

Contoh memerlukan referensi paket untuk Microsoft.Extensions.Http aplikasi mandiri Blazor WebAssembly atau Client aplikasi solusi yang dihosting Blazor WebAssembly .

Catatan

Untuk panduan tentang menambahkan paket ke aplikasi .NET, lihat artikel di bagian Menginstal dan mengelola paket di Alur kerja konsumsi paket (dokumentasi NuGet). Konfirmasikan versi paket yang benar di NuGet.org.

Dalam portal Azure, berikan izin yang didelegasikan (cakupan)† untuk data Microsoft Graph yang harus dapat diakses aplikasi atas nama pengguna. Untuk contoh dalam artikel ini, pendaftaran aplikasi harus menyertakan izin yang didelegasikan untuk membaca data pengguna (Microsoft.Graph>User.Read cakupan dalam izin API, Jenis: Didelegasikan). Cakupan memungkinkan User.Read pengguna untuk masuk ke aplikasi dan memungkinkan aplikasi membaca profil dan informasi perusahaan pengguna yang masuk. Untuk informasi selengkapnya, lihat Gambaran Umum izin dan persetujuan di platform Microsoft identity dan Gambaran Umum izin Microsoft Graph.

†Permissions dan cakupan berarti hal yang sama dan digunakan secara bergantian dalam dokumentasi keamanan dan portal Azure. Kecuali teks mengacu pada portal Azure, artikel ini menggunakan cakupan/ saat merujuk ke izin Grafik.

Cakupan tidak peka huruf besar/kecil, jadi User.Read sama user.readdengan . Jangan ragu untuk menggunakan salah satu format, tetapi kami merekomendasikan pilihan yang konsisten di seluruh kode aplikasi.

Setelah menambahkan cakupan Microsoft Graph API ke pendaftaran aplikasi di portal Azure, tambahkan konfigurasi pengaturan aplikasi berikut ke wwwroot/appsettings.json file di aplikasi, yang mencakup URL dasar Grafik dengan versi dan cakupan Microsoft Graph. Dalam contoh berikut, User.Read cakupan ditentukan untuk contoh di bagian selanjutnya dari artikel ini. Cakupan tidak peka huruf besar/kecil.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com",
  "Version": "{VERSION}",
  "Scopes": [
    "user.read"
  ]
}

Dalam contoh sebelumnya, {VERSION} tempat penampung adalah versi Microsoft Graph API (misalnya: v1.0).

Berikut ini adalah contoh file konfigurasi lengkap wwwroot/appsettings.json untuk aplikasi yang menggunakan ME-ID sebagai penyedianya identity , di mana membaca data pengguna (user.read cakupan) ditentukan untuk Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com",
    "Version": "v1.0",
    "Scopes": [
      "user.read"
    ]
  }
}

Dalam contoh sebelumnya, {TENANT ID} tempat penampung adalah ID Direktori (penyewa), dan {CLIENT ID} tempat penampung adalah ID Aplikasi (klien). Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Buat konfigurasi kelas dan proyek berikut GraphAuthorizationMessageHandler dalam Program file untuk bekerja dengan Graph API. URL dasar dan cakupan disediakan untuk handler dari konfigurasi.

GraphAuthorizationMessageHandler.cs:

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

namespace BlazorSample;

public class GraphAuthorizationMessageHandler : AuthorizationMessageHandler
{
    public GraphAuthorizationMessageHandler(IAccessTokenProvider provider,
        NavigationManager navigation, IConfiguration config)
        : base(provider, navigation)
    {
        ConfigureHandler(
            authorizedUrls: [ 
                string.Join("/",
                    config.GetSection("MicrosoftGraph")["BaseUrl"] ??
                        "https://graph.microsoft.com",
                    config.GetSection("MicrosoftGraph")["Version"] ??
                        "v1.0")
            ],
            scopes: config.GetSection("MicrosoftGraph:Scopes")
                        .Get<List<string>>() ?? [ "user.read" ]);
    }
}

Garis miring berikutnya (/) URL resmi diperlukan. Kode sebelumnya membangun URL resmi berikut dari konfigurasi pengaturan aplikasi atau default ke URL resmi berikut jika konfigurasi pengaturan aplikasi hilang: https://graph.microsoft.com/v1.0/.

Program Dalam file, konfigurasikan bernama HttpClient untuk Graph API:

builder.Services.AddTransient<GraphAuthorizationMessageHandler>();

builder.Services.AddHttpClient("GraphAPI",
        client => client.BaseAddress = new Uri(
            string.Join("/",
                builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
                    "https://graph.microsoft.com",
                builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
                    "v1.0",
                string.Empty)))
    .AddHttpMessageHandler<GraphAuthorizationMessageHandler>();

Dalam contoh sebelumnya, GraphAuthorizationMessageHandler DelegatingHandler terdaftar sebagai layanan sementara untuk AddHttpMessageHandler. Pendaftaran sementara direkomendasikan untuk IHttpClientFactory, yang mengelola cakupan DI-nya sendiri. Untuk informasi selengkapnya, lihat sumber daya berikut:

Garis miring berikutnya (/) pada alamat dasar diperlukan. Dalam kode sebelumnya, argumen string.Join ketiga adalah string.Empty memastikan garis miring berikutnya ada: https://graph.microsoft.com/v1.0/.

Memanggil Graph API dari komponen menggunakan bernama HttpClient

Kelas UserInfo.cs menunjuk properti profil pengguna yang diperlukan dengan JsonPropertyNameAttribute atribut dan nama JSON yang digunakan oleh ME-ID. Contoh berikut menyiapkan properti untuk nomor ponsel pengguna dan lokasi kantor.

UserInfo.cs:

using System.Text.Json.Serialization;

namespace BlazorSample;

public class UserInfo
{
    [JsonPropertyName("mobilePhone")]
    public string? MobilePhone { get; set; }

    [JsonPropertyName("officeLocation")]
    public string? OfficeLocation { get; set; }
}

Dalam komponen berikut UserData , HttpClient dibuat untuk Graph API untuk mengeluarkan permintaan data profil pengguna. Sumber me daya (me) ditambahkan ke URL dasar dengan versi untuk permintaan Graph API. Data JSON yang dikembalikan oleh Graph dideserialisasi ke UserInfo dalam properti kelas. Dalam contoh berikut, nomor ponsel diperoleh. Anda dapat menambahkan kode serupa untuk menyertakan lokasi kantor profil ME-ID pengguna jika Anda mau (userInfo.OfficeLocation). Jika permintaan token akses gagal, pengguna diarahkan untuk masuk ke aplikasi untuk token akses baru.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@attribute [Authorize]
@inject IConfiguration Config
@inject IHttpClientFactory ClientFactory

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(userInfo?.MobilePhone))
{
    <p>Mobile Phone: @userInfo.MobilePhone</p>
}

@code {
    private UserInfo? userInfo;

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

            userInfo = await client.GetFromJsonAsync<UserInfo>("me");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

Tip

Untuk menambahkan pengguna ke aplikasi, lihat bagian Menetapkan pengguna ke pendaftaran aplikasi dengan atau tanpa peran aplikasi.

Urutan berikut menjelaskan alur pengguna baru untuk cakupan Graph API:

  1. Pengguna baru masuk ke aplikasi untuk pertama kalinya.
  2. Pengguna menyetujui untuk menggunakan aplikasi di UI persetujuan Azure.
  3. Pengguna mengakses halaman komponen yang meminta data Graph API untuk pertama kalinya.
  4. Pengguna dialihkan ke UI persetujuan Azure untuk menyetujui cakupan Graph API.
  5. Data pengguna Graph API dikembalikan.

Jika Anda lebih suka provisi cakupan tersebut (persetujuan untuk cakupan Graph API) terjadi pada masuk awal, berikan cakupan ke autentikasi MSAL sebagai cakupan token akses default dalam Program file:

+ var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
+     .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);

+   foreach (var scope in scopes)
+   {
+       options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
+   }
});

Penting

Lihat bagian DefaultAccessTokenScopes versus AdditionalScopesToConsent untuk penjelasan tentang mengapa kode sebelumnya menggunakan DefaultAccessTokenScopes untuk menambahkan cakupan daripada AdditionalScopesToConsent.

Saat perubahan sebelumnya dilakukan pada aplikasi, alur pengguna mengadopsi urutan berikut:

  1. Pengguna baru masuk ke aplikasi untuk pertama kalinya.
  2. Pengguna menyetujui untuk menggunakan cakupan API aplikasi dan Graph di UI persetujuan Azure.
  3. Pengguna mengakses halaman komponen yang meminta data Graph API untuk pertama kalinya.
  4. Data pengguna Graph API dikembalikan.

Saat menguji dengan Graph API secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie yang berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Menyesuaikan klaim pengguna menggunakan nama HttpClient

Dalam contoh berikut, aplikasi membuat nomor ponsel dan klaim lokasi kantor untuk pengguna dari data profil pengguna ME-ID mereka. Aplikasi harus memiliki cakupan Graph API yang User.Read dikonfigurasi dalam ME-ID. Uji akun pengguna di ME-ID memerlukan entri untuk nomor ponsel dan lokasi kantor, yang dapat ditambahkan melalui portal Azure ke profil pengguna mereka.

Jika Anda belum menambahkan UserInfo kelas ke aplikasi dengan mengikuti panduan sebelumnya dalam artikel ini, tambahkan kelas berikut dan tetapkan properti profil pengguna yang diperlukan dengan JsonPropertyNameAttribute atribut dan nama JSON yang digunakan oleh ME-ID. Contoh berikut menyiapkan properti untuk nomor ponsel pengguna dan lokasi kantor.

UserInfo.cs:

using System.Text.Json.Serialization;

namespace BlazorSample;

public class UserInfo
{
    [JsonPropertyName("mobilePhone")]
    public string? MobilePhone { get; set; }

    [JsonPropertyName("officeLocation")]
    public string? OfficeLocation { get; set; }
}

Di pabrik akun pengguna kustom berikut:

  • ILogger (logger) disertakan untuk kenyamanan jika Anda ingin mencatat informasi atau kesalahan dalam metode .CreateUserAsync
  • AccessTokenNotAvailableException Jika dilemparkan, pengguna dialihkan ke identity penyedia untuk masuk ke akun mereka. Tindakan tambahan atau berbeda dapat diambil saat meminta token akses gagal. Misalnya, aplikasi dapat mencatat AccessTokenNotAvailableException dan membuat tiket dukungan untuk penyelidikan lebih lanjut.
  • Kerangka kerja mewakili RemoteUserAccount akun pengguna. Jika aplikasi memerlukan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom untuk RemoteUserAccount dalam kode berikut.

CustomAccountFactory.cs:

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

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IHttpClientFactory clientFactory,
        ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IHttpClientFactory clientFactory = clientFactory;

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null && 
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                try
                {
                    var client = clientFactory.CreateClient("GraphAPI");

                    var userInfo = await client.GetFromJsonAsync<UserInfo>("me");

                    if (userInfo is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            userInfo.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            userInfo.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Autentikasi MSAL dikonfigurasi untuk menggunakan pabrik akun pengguna kustom. Mulailah dengan mengonfirmasi bahwa Program file menggunakan Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Program Dalam file, temukan panggilan ke AddMsalAuthentication metode ekstensi. Perbarui kode ke yang berikut, yang menyertakan panggilan ke AddAccountClaimsPrincipalFactory yang menambahkan pabrik utama klaim akun dengan CustomAccountFactory.

Jika aplikasi menggunakan kelas akun pengguna kustom yang memperluas RemoteUserAccount, tukar kelas akun pengguna kustom aplikasi Anda dengan RemoteUserAccount dalam kode berikut.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState, 
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount, 
        CustomAccountFactory>();

Contoh sebelumnya adalah untuk aplikasi yang menggunakan autentikasi ME-ID dengan MSAL. Pola serupa ada untuk otentikasi OIDC dan API. Untuk informasi selengkapnya, lihat contoh di bagian Kustomisasi pengguna dengan klaim payload dari artikel skenario keamanan tambahan ASP.NET CoreBlazor WebAssembly.

Anda dapat menggunakan komponen berikut UserClaims untuk mempelajari klaim pengguna setelah pengguna mengautentikasi dengan ME-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Tambahkan tautan ke halaman komponen di NavMenu komponen (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Saat menguji dengan Graph API secara lokal, sebaiknya gunakan sesi browser InPrivate/incognito baru untuk setiap pengujian untuk mencegah cookie yang berlama-lama mengganggu pengujian. Untuk informasi selengkapnya, lihat Mengamankan aplikasi mandiri ASP.NET Core Blazor WebAssembly dengan ID Microsoft Entra.

Menetapkan pengguna ke pendaftaran aplikasi dengan atau tanpa peran aplikasi

Anda dapat menambahkan pengguna ke pendaftaran aplikasi dan menetapkan peran kepada pengguna dengan langkah-langkah berikut di portal Azure.

Untuk menambahkan pengguna, pilih Pengguna dari area ME-ID portal Azure:

  1. Pilih Pengguna>baru Buat pengguna baru.
  2. Gunakan templat Buat pengguna.
  3. Berikan informasi pengguna di area tersebut Identity .
  4. Anda dapat membuat kata sandi awal atau menetapkan kata sandi awal yang diubah pengguna saat mereka masuk untuk pertama kalinya. Jika Anda menggunakan kata sandi yang dihasilkan oleh portal, catat sekarang.
  5. Pilih Buat untuk membuat pengguna. Saat Buat antarmuka pengguna baru ditutup, pilih Refresh untuk memperbarui daftar pengguna dan memperlihatkan pengguna baru.
  6. Untuk contoh dalam artikel ini, tetapkan nomor ponsel ke pengguna baru dengan memilih nama mereka dari daftar pengguna, memilih Properti, dan mengedit informasi kontak untuk memberikan nomor telepon seluler.

Untuk menetapkan pengguna ke aplikasi tanpa peran aplikasi:

  1. Di area ME-ID portal Azure, buka aplikasi Enterprise.
  2. Pilih aplikasi dari daftar.
  3. Pilih Pengguna dan grup.
  4. Pilih Tambahkan pengguna/grup.
  5. Pilih pengguna.
  6. Pilih tombol Tetapkan.

Untuk menetapkan pengguna ke aplikasi dengan peran aplikasi:

  1. Tambahkan peran ke pendaftaran aplikasi di portal Azure mengikuti panduan di ASP.NET Core Blazor WebAssembly dengan grup dan peran ID Microsoft Entra.
  2. Di area ME-ID portal Azure, buka aplikasi Enterprise.
  3. Pilih aplikasi dari daftar.
  4. Pilih Pengguna dan grup.
  5. Pilih Tambahkan pengguna/grup.
  6. Pilih pengguna dan pilih peran mereka untuk mengakses aplikasi. Beberapa peran ditetapkan kepada pengguna dengan mengulangi proses penambahan pengguna ke aplikasi hingga semua peran untuk pengguna ditetapkan. Pengguna dengan beberapa peran dicantumkan sekali untuk setiap peran yang ditetapkan dalam daftar Pengguna dan grup pengguna untuk aplikasi.
  7. Pilih tombol Tetapkan.

DefaultAccessTokenScopes versus AdditionalScopesToConsent

Contoh dalam artikel ini menyediakan cakupan Graph API dengan DefaultAccessTokenScopes, bukan AdditionalScopesToConsent.

AdditionalScopesToConsent tidak digunakan karena tidak dapat menyediakan cakupan Graph API untuk pengguna saat mereka masuk ke aplikasi untuk pertama kalinya dengan MSAL melalui UI persetujuan Azure. Ketika pengguna mencoba mengakses Graph API untuk pertama kalinya dengan Graph SDK, mereka dihadapkan dengan pengecualian:

Microsoft.Graph.Models.ODataErrors.ODataError: Access token is empty.

Setelah pengguna memprovisikan cakupan Graph API yang disediakan melalui DefaultAccessTokenScopes, aplikasi dapat digunakan AdditionalScopesToConsent untuk masuk pengguna berikutnya. Namun, mengubah kode aplikasi tidak masuk akal untuk aplikasi produksi yang memerlukan penambahan berkala pengguna baru dengan cakupan Grafik yang didelegasikan atau menambahkan cakupan Graph API baru yang didelegasikan ke aplikasi.

Diskusi sebelumnya tentang cara menyediakan cakupan untuk akses Graph API saat pengguna pertama kali masuk ke aplikasi hanya berlaku untuk:

  • Aplikasi yang mengadopsi Graph SDK.
  • Aplikasi yang menggunakan akses api bernama HttpClient untuk Graph yang meminta pengguna untuk menyetujui cakupan Graph pada masuk pertama mereka ke aplikasi.

Saat menggunakan nama HttpClient yang tidak meminta pengguna untuk menyetujui cakupan Graph pada masuk pertama mereka, pengguna dialihkan ke UI persetujuan Azure untuk lingkup Graph API saat pertama kali meminta akses ke Graph API melalui DelegatingHandler yang telah dikonfigurasi sebelumnya, bernama HttpClient. Saat cakupan Grafik tidak disetujui pada awalnya dengan pendekatan bernamaHttpClient, tidak juga AdditionalScopesToConsent tidak DefaultAccessTokenScopes dipanggil oleh aplikasi. Untuk informasi selengkapnya, lihat cakupan bernama HttpClient di artikel ini.

Solusi yang dihosting Blazor WebAssembly

Contoh dalam artikel ini berkaitan dengan penggunaan Graph SDK atau bernama HttpClient dengan Graph API langsung dari aplikasi mandiri Blazor WebAssembly atau langsung dari Client aplikasi solusi yang dihostingBlazor WebAssembly. Skenario tambahan yang tidak dibahas oleh artikel ini adalah untuk aplikasi solusi yang Client dihosting untuk memanggil Server aplikasi solusi melalui API web, lalu Server aplikasi menggunakan Graph SDK/API untuk memanggil Microsoft Graph dan mengembalikan data ke Client aplikasi. Meskipun ini adalah pendekatan yang didukung, ini tidak dibahas oleh artikel ini. Jika Anda ingin mengadopsi pendekatan ini:

  • Ikuti panduan dalam Memanggil API web dari aplikasi ASP.NET Core Blazor untuk aspek API web tentang mengeluarkan permintaan ke Server aplikasi dari Client aplikasi dan mengembalikan data ke Client aplikasi.
  • Ikuti panduan dalam dokumentasi Microsoft Graph utama untuk menggunakan Graph SDK dengan aplikasi ASP.NET Core biasa, yang dalam skenario ini adalah Server aplikasi solusi. Jika Anda menggunakan Blazor WebAssembly templat proyek untuk membuat solusi yang dihosting Blazor WebAssembly (ASP.NET Core Hosted/-h|--hosted) dengan otorisasi organisasi (organisasi tunggal/SingleOrg atau beberapa organisasi/MultiOrg) dan opsi Microsoft Graph (platform>Microsoft identity Connected Services>Tambahkan izin Microsoft Graph di Visual Studio atau --calls-graph opsi dengan perintah .NET CLI),Server dotnet new aplikasi solusi dikonfigurasi untuk menggunakan Graph SDK saat solusi dibuat dari templat proyek.

Sumber Daya Tambahan:

Panduan Umum

  • Dokumentasi Microsoft Graph
  • Aplikasi sampel Blazor WebAssembly Microsoft Graph: Sampel ini menunjukkan cara menggunakan Microsoft Graph .NET SDK untuk mengakses data di Office 365 dari Blazor WebAssembly aplikasi.
  • Buat aplikasi .NET dengan tutorial Microsoft Graph dan sampel Microsoft Graph ASP.NET aplikasi Core: Meskipun sumber daya ini tidak langsung berlaku untuk memanggil Graph dari aplikasi sisiBlazor WebAssembly klien, konfigurasi aplikasi ME-ID dan praktik pengodean Microsoft Graph di sumber daya tertaut relevan untuk aplikasi mandiri Blazor WebAssembly dan harus dikonsultasikan untuk praktik terbaik umum.
  • Dokumentasi Microsoft Graph
  • Aplikasi sampel Blazor WebAssembly Microsoft Graph: Sampel ini menunjukkan cara menggunakan Microsoft Graph .NET SDK untuk mengakses data di Office 365 dari Blazor WebAssembly aplikasi.
  • Buat aplikasi .NET dengan tutorial Microsoft Graph dan sampel Microsoft Graph ASP.NET aplikasi Core: Sumber daya ini paling sesuai untuk solusi yang dihostingBlazor WebAssembly, di mana aplikasi dikonfigurasi Server untuk mengakses Microsoft Graph sebagai aplikasi ASP.NET Core biasa atas Client nama aplikasi. Aplikasi ini Client menggunakan API web untuk membuat permintaan ke Server aplikasi untuk data Graph. Meskipun sumber daya ini tidak secara langsung berlaku untuk memanggil Graph dari aplikasi sisiBlazor WebAssembly klien, konfigurasi aplikasi ME-ID dan praktik pengkodian Microsoft Graph dalam sumber daya yang ditautkan relevan untuk aplikasi mandiri Blazor WebAssembly dan harus dikonsultasikan untuk praktik terbaik umum.

Panduan keamanan