注意
這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 關於目前版本,請參閱 本文的 .NET 10 版本。
本文說明如何在 Blazor WebAssembly 應用程式中使用 Microsoft Graph,讓應用程式能夠存取 Microsoft 雲端資源。
涵蓋兩種方法:
Graph SDK:Microsoft Graph SDK 簡化建置可存取 Microsoft Graph 的高品質、有效率且可復原的應用程式。 選取本文頂端的 [Graph SDK] 按鈕,即可採用此方法。
使用 圖形 API 的具名 HttpClient:具名
HttpClient可直接對 Microsoft Graph 發出 Microsoft Graph API 要求。 選取本文頂端的 Named HttpClient with 圖形 API 按鈕,即可採用此方法。
本文中的指引並非用來取代 Microsoft Graph 文件與其他 Microsoft 文件集中的 Azure 安全性指引。 在生產環境中實作 Microsoft Graph 之前,請先評估本文其他資源一節中的安全性指引。 請依照 Microsoft 最佳做法,限縮應用程式的漏洞。
下列 Microsoft Graph 和 Azure 範例提供了 Microsoft Graph 和 Blazor WebAssembly 搭配使用的其他作法:
-
Microsoft Graph 範例 Blazor WebAssembly 應用程式:此範例透過 Microsoft Graph SDK 採用 Factory 式方法,以取得 Office 365 資料。 此範例使用預設的 HttpClient 來提出 Graph 用戶端要求。 如果您需要使用預設的 HttpClient 搭配應用程式 (
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)) 的基底址用於其他用途,例如從應用程式的 Web 根目錄載入資料,請考慮重構 Graph 用戶端處理站以使用 Graph 要求專用的具名HttpClient名稱。 -
.NET 8 Blazor WebAssembly 中的 ASP.NET Core |獨立應用程式 |使用者登入、受保護的 Web API 存取權 (Microsoft Graph) |Microsoft身分識別平臺:此範例是 漸進式 Web 應用程式 (PWA), 會使用授權訊息處理程式並 HttpClient 取得 Graph 數據。 如同上述範例,此範例也會使用預設的 HttpClient 來提出 Graph 用戶端要求。 此範例透過元件中的 Microsoft Graph API 要求,以 JSON 的形式擷取使用者帳戶資料,而不是使用 Microsoft Graph SDK。 此技術類似於本文中使用 圖形 API 的具名 HttpClient 方法 (請使用本文頂端的按鈕來查看指引),不同之處在於本文的指引使用 Graph 要求專用的具名
HttpClient。
若要對上述兩個範例的其中之一提供意見反應,請在範例的 GitHub 存放庫上提出問題。 如果您要對 Azure 範例提出問題,請在開放式留言中提供連至該範例的連結,因為 Azure 範例存放庫 (Azure-Samples) 包含許多範例。 詳述問題並視需要包含範例程序碼。 將可重現問題或錯誤的精簡應用程式放入 GitHub。 請務必先從範例中移除 Azure 帳戶設定資料,再將其提交至公用存放庫。
若要對本文或 ASP.NET Core 提供意見反應或尋求協助,請參閱 ASP.NET Core Blazor 基本概念。
重要
本文所述的案例適用於使用 Microsoft Entra (ME-ID) 作為識別提供者,而不是 AAD B2C。 目前不支援搭配用戶端 Blazor WebAssembly 應用程式和 AAD B2C 識別提供者使用 Microsoft Graph,因為應用程式需要用戶端密碼 (client secret),而此密碼無法在用戶端 Blazor 應用程式中受到保護。 針對使用 圖形 API 的 AAD B2C 獨立 Blazor WebAssembly 應用程式,建立後端伺服器 (Web) API 以代表使用者存取 圖形 API。 用戶端應用程式會驗證並授權使用者呼叫 Web API,以安全地存取 Microsoft Graph,並將資料從伺服器端 Web API 傳回用戶端 Blazor 應用程式。 用戶端密碼會在伺服器型 Web API 中安全地維護,而不是在用戶端上的 Blazor 應用程式中。 永不將用戶端密碼儲存在用戶端 Blazor 應用程式中。
注意
自 2025 年 5 月 1 日起,Azure Active Directory B2C 不再提供給新客戶提供服務。 欲了解更多資訊,請參閱 Azure AD B2C:常見問題(FAQ)。
支援使用託管的 Blazor WebAssembly 應用程式;其中,Server 應用程式會使用 Graph SDK/API 透過 Web API 將 Graph 資料提供給 Client 應用程式。 如需詳細資訊,請參閱本文的託管的 Blazor WebAssembly 解決方案一節。
本文中的範例會利用新的 .NET/C# 功能。 在.NET 7 或更早版本中使用這些範例時,需要略為修改。 不過,對於所有 ASP.NET Core 版本,涉及與 Microsoft Graph 互動的文字和程式碼範例都相同。
以下指引適用於 Microsoft Graph v5 或更新版本。
在 Blazor 應用程式中使用的 Microsoft Graph SDK,稱為 Microsoft Graph .NET 用戶端程式庫。
Graph SDK 範例需要在獨立的 Blazor WebAssembly 應用程式中加入下列套件參考項目。 如果應用程式已啟用 MSAL 驗證,則前兩個套件都已被參考,例如依照 使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式 中的指引建立應用程式時。
Graph SDK 範例需要在獨立的 Blazor WebAssembly 應用程式或託管的 Blazor WebAssembly 解決方案中的 Client 應用程式內參考下列套件。 如果應用程式已啟用 MSAL 驗證,則前兩個套件已被參考,例如,在依照 使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式 中的指引建立應用程式時。
Microsoft.AspNetCore.Components.WebAssembly.AuthenticationMicrosoft.Authentication.WebAssembly.MsalMicrosoft.Extensions.HttpMicrosoft.Graph
注意
Microsoft.Authentication.WebAssembly.Msal 套件 可傳遞地將 Microsoft.AspNetCore.Components.WebAssembly.Authentication 套件 加入應用程式。
在 Azure 入口網站中,為 Microsoft Graph 資料授與委派的權限 (範圍)†,應用程式應該能夠代表使用者存取。 針對本文中的範例,應用程式註冊應包含讀取使用者資料的委派權限(在 API permissions 中的 Microsoft.Graph>User.Read 範圍,類型:Delegated)。
User.Read 範圍允許使用者登入應用程式,並且允許應用程式讀取已登入使用者的設定檔和公司資訊。 如需詳細資訊,請參閱 Microsoft 身分識別平臺 的許可權和同意概觀和 Microsoft Graph 許可權概觀。
†權限和範圍代表相同的事項,在安全性文件和 Azure 入口網站中交換使用。 除非本文提到的是 Azure 入口網站,否則在提到 Graph 權限時,本文會使用 scope/scopes。
範圍不區分大小寫,因此 User.Read 與 user.read 相同。 請隨意使用任一格式,但建議在應用程式碼之間選擇一致的格式。
在 Azure 入口網站的應用程式註冊中新增 Microsoft Graph API 範圍之後,請將下列應用程式設定組態新增至 wwwroot/appsettings.json 檔案,其中包括 Graph 基底 URL 以及 Microsoft Graph 版本和範圍。 在下列範例中,會針對本文後續幾節中的範例指定 User.Read 範圍。 範圍不區分大小寫。
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
在上述範例中,{VERSION} 預留位置是 Microsoft 圖形 API 的版本 (例如:v1.0)。
以下是應用程式的完整 wwwroot/appsettings.json 組態檔範例,該應用程式會使用 ME-ID 作為其識別提供者,其中已針對 Microsoft Graph 指定讀取使用者資料 (user.read 範圍) :
{
"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"
]
}
}
在上述範例中,{TENANT ID} 預留位置是目錄 (租用戶) 識別碼,而 {CLIENT ID} 預留位置是應用程式 (用戶端) 識別碼。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
將下列 GraphClientExtensions 類別新增至獨立應用程式。 範圍會在 AuthenticateRequestAsync 方法中提供給 AccessTokenRequestOptions 的 Scopes 屬性。
將下列 GraphClientExtensions 類別新增至獨立應用程式,或託管 Blazor WebAssembly解決方案的 Client 應用程式。 範圍會在 AuthenticateRequestAsync 方法中提供給 AccessTokenRequestOptions 的 Scopes 屬性。
當未取得存取權杖時,以下程式碼不會為圖請求設定 Bearer 授權標頭。
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}");
}
}
}
}
重要
請參閱 DefaultAccessTokenScopes 與 AdditionalScopesToConsent 一節,以了解上述程式碼為何使用 來加入範圍,而非使用 。
在 Program 檔案中,使用 AddGraphClient 擴充方法新增 Graph 用戶端服務與設定。 如果應用程式設定檔中找不到這些設定,下列程式碼會預設為 1.0 版 Microsoft Graph 基底位址與 User.Read 範圍:
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);
使用 Graph SDK 從元件呼叫圖形 API
下列 UserData 元件會使用插入的 GraphServiceClient 取得使用者的 ME-ID 設定檔資料,並顯示其行動電話號碼。
對於您在 ME-ID 中建立的任何測試使用者,請確定您在 Azure 入口網站中為使用者的 ME-ID 設定檔提供了行動電話號碼。
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();
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
提示
若要將使用者新增到應用程式,請參閱將使用者指派給應用程式註冊(無論是否使用應用程式角色)一節。
在本機使用 Graph SDK 進行測試時,我們建議每次測試都使用新的 InPrivate/incognito 瀏覽器工作階段,以避免殘留的 Cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
使用 Graph SDK 自訂使用者宣告
在以下範例中,應用程式會根據 ME-ID 使用者設定檔中的資料,為使用者產生行動電話號碼和辦公室位置宣告。 應用程式必須在 ME-ID 中設定 User.Read 圖形 API 範圍。 此案例的任何測試使用者在其 ME-ID 設定檔中都必須有行動電話號碼和辦公室位置 (可透過 Azure 入口網站來新增)。
在下列自訂使用者帳戶處理站中:
- 為了方便起見,系統包含了 ILogger(
logger),以便您在CreateUserAsync方法中記錄資訊或錯誤。 - 如果發生 AccessTokenNotAvailableException,則會將使用者重新導向至身份提供者以登入使用者帳戶。 要求存取權杖失敗時,可以採取其他或不同的動作。 例如,應用程式可以記錄 AccessTokenNotAvailableException 並建立支援單,以供進一步調查。
- 架構的 RemoteUserAccount 代表使用者帳戶。 如果應用程式需要擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將您的自訂使用者帳戶類別替換為 RemoteUserAccount。
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;
}
}
設定 MSAL 驗證,以使用自訂使用者帳戶處理站。
確認 Program 檔案使用的是 Microsoft.AspNetCore.Components.WebAssembly.Authentication 命名空間:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
本節中的範例是基於透過 MicrosoftGraph 檔案中的 wwwroot/appsettings.json 區段讀取基底 URL 以及應用程式設定的版本和範圍的方法。 依照本文先前的指引,Program 檔案中應已有以下幾行:
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 檔案中,尋找對 AddMsalAuthentication 擴充方法的呼叫。 將程式碼更新為以下內容,其中包含對 AddAccountClaimsPrincipalFactory 的呼叫,以加入搭配 CustomAccountFactory 的帳戶宣告主體處理站。
如果應用程式會使用擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將自訂使用者帳戶類別替換為 RemoteUserAccount。
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
您可以在使用者向 ME-ID 進行驗證後,使用下列 UserClaims 元件審視使用者的宣告:
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;
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
在本機使用 Graph SDK 進行測試時,我們建議每次測試都使用新的 InPrivate/incognito 瀏覽器工作階段,以避免殘留的 Cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
下列指引適用於 Microsoft Graph v4。 如果你正在將應用程式從 SDK v4 升級到 v5 或更高版本,請參考以下資源:
- Microsoft Graph .NET SDK v5 變更日誌與升級指南
-
Microsoft Graph .NET SDK 版本(
microsoftgraph/msgraph-sdk-dotnetGitHub 倉庫)(參見 6.0.0 破壞性變更備註)
在 Blazor 應用程式中使用的 Microsoft Graph SDK,稱為 Microsoft Graph .NET 用戶端程式庫。
Graph SDK 範例需要在獨立 Blazor WebAssembly 應用程式中加入下列套件參考。 如果應用程式已啟用 MSAL 驗證,則已參考前兩個套件,例如,遵循使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式中的指導建立應用程式時。
Graph SDK 範例需要在獨立的 Blazor WebAssembly 應用程式或託管的 Blazor WebAssembly 解決方案中的 Client 應用程式內包含下列套件參考。 如果應用程式已啟用 MSAL 驗證,則已參考前兩個套件,例如,遵循使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式中的指導建立應用程式時。
Microsoft.AspNetCore.Components.WebAssembly.AuthenticationMicrosoft.Authentication.WebAssembly.MsalMicrosoft.Extensions.HttpMicrosoft.Graph
在 Azure 入口網站中,為 Microsoft Graph 資料授與委派的權限 (範圍)†,應用程式應該能夠代表使用者存取。 針對本文中的範例,應用程式註冊應包含讀取使用者資料的委派權限(在 API permissions 中的 Microsoft.Graph>User.Read 範圍,類型:Delegated)。
User.Read 範圍允許使用者登入應用程式,並且允許應用程式讀取已登入使用者的設定檔和公司資訊。 如需詳細資訊,請參閱 Microsoft 身分識別平臺 的許可權和同意概觀和 Microsoft Graph 許可權概觀。
†權限和範圍代表相同的事項,在安全性文件和 Azure 入口網站中交換使用。 除非本文提到的是 Azure 入口網站,否則在提到 Graph 權限時,本文會使用 scope/scopes。
範圍不區分大小寫,因此 User.Read 與 user.read 相同。 請隨意使用任一格式,但建議在應用程式碼之間選擇一致的格式。
在 Azure 入口網站的應用程式註冊中新增 Microsoft Graph API 範圍之後,請將下列應用程式設定組態新增至 wwwroot/appsettings.json 檔案,其中包括 Graph 基底 URL 以及 Microsoft Graph 版本和範圍。 在下列範例中,會針對本文後續幾節中的範例指定 User.Read 範圍。 範圍不區分大小寫。
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
在上述範例中,{VERSION} 預留位置是 Microsoft 圖形 API 的版本 (例如:v1.0)。
以下是應用程式的完整 wwwroot/appsettings.json 組態檔範例,該應用程式會使用 ME-ID 作為其識別提供者,其中已針對 Microsoft Graph 指定讀取使用者資料 (user.read 範圍) :
{
"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"
]
}
}
在上述範例中,{TENANT ID} 預留位置是目錄 (租用戶) 識別碼,而 {CLIENT ID} 預留位置是應用程式 (用戶端) 識別碼。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
將下列 GraphClientExtensions 類別新增至獨立應用程式。 在 AuthenticateRequestAsync 方法中,範圍會提供給 AccessTokenRequestOptions 的 Scopes 屬性。
IHttpProvider.OverallTimeout 會從預設值 100 秒擴充至 300 秒,讓 HttpClient 有更多時間接收來自 Microsoft Graph 的回應。
將下列 GraphClientExtensions 類別新增至獨立應用程式,或託管 Blazor WebAssembly解決方案的 Client 應用程式。 範圍會在 AuthenticateRequestAsync 方法中提供給 AccessTokenRequestOptions 的 Scopes 屬性。
IHttpProvider.OverallTimeout 會從預設值 100 秒擴充至 300 秒,讓 HttpClient 有更多時間接收來自 Microsoft Graph 的回應。
當未取得存取權杖時,以下程式碼不會為圖請求設定 Bearer 授權標頭。
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()
{
}
}
}
重要
請參閱 DefaultAccessTokenScopes 與 AdditionalScopesToConsent 一節,以了解上述程式碼為何使用 來加入範圍,而非使用 。
在 Program 檔案中,使用 AddGraphClient 擴充方法新增 Graph 用戶端服務和設定:
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);
使用 Graph SDK 從元件呼叫圖形 API
下列 UserData 元件會使用插入的 GraphServiceClient 取得使用者的 ME-ID 設定檔資料,並顯示其行動電話號碼。 對於您在 ME-ID 中建立的任何測試使用者,請確定您在 Azure 入口網站中為使用者的 ME-ID 設定檔提供了行動電話號碼。
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();
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
提示
若要將使用者新增到應用程式,請參閱將使用者指派給應用程式註冊(無論是否使用應用程式角色)一節。
在本機使用 Graph SDK 進行測試時,我們建議每次測試都使用新的 InPrivate/無痕瀏覽器工作階段,以避免殘留的 Cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
使用 Graph SDK 自訂使用者宣告
在下列範例中,應用程式會根據使用者的 ME-ID 使用者個人資料設定檔中的資料,為其建立行動電話號碼和辦公室地點宣告。 應用程式必須在 ME-ID 中設定 User.Read 圖形 API 範圍。 此案例的任何測試使用者在其 ME-ID 設定檔中都必須有行動電話號碼和辦公室位置 (可透過 Azure 入口網站來新增)。
在下列自訂使用者帳戶處理站中:
- 納入了 ILogger (
logger),以便您在CreateUserAsync方法中記錄資訊或錯誤。 - 如果發生 AccessTokenNotAvailableException,則會將使用者重新導向至身份提供者以登入使用者帳戶。 要求存取權杖失敗時,可以採取其他或不同的動作。 例如,應用程式可以記錄 AccessTokenNotAvailableException,並建立支援單,以便進一步調查。
- 架構的 RemoteUserAccount 代表使用者帳戶。 如果應用程式需要擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將您的自訂使用者帳戶類別替換為 RemoteUserAccount。
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;
}
}
設定 MSAL 驗證,以使用自訂使用者帳戶處理站。
確認 Program 檔案使用的是 Microsoft.AspNetCore.Components.WebAssembly.Authentication 命名空間:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
本節中的範例是基於透過 MicrosoftGraph 檔案中的 wwwroot/appsettings.json 區段讀取基底 URL 以及應用程式設定的版本和範圍的方法。 依照本文先前的指引,Program 檔案中應已有以下幾行:
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 檔案中,尋找對 AddMsalAuthentication 擴充方法的呼叫。 將程式碼更新為以下內容,包括呼叫 AddAccountClaimsPrincipalFactory 以使用 CustomAccountFactory 新增帳戶宣告主體處理站。
如果應用程式會使用擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將自訂使用者帳戶類別替換為 RemoteUserAccount。
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
您可以在使用者向 ME-ID 進行驗證後,使用下列 UserClaims 元件審視使用者的宣告:
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;
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
在本機使用 Graph SDK 進行測試時,我們建議每次測試都使用新的 InPrivate/incognito 瀏覽器工作階段,以避免殘留的 Cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
下列範例使用名為 HttpClient 的 圖形 API 呼叫來取得使用者的行動電話號碼,以處理通話,或自訂使用者宣告,使其包含行動電話號碼宣告和辦公室地點宣告。
這些範例需要適用於獨立式 Blazor WebAssembly 應用程式的 Microsoft.Extensions.Http 套件參考。
這些範例需要針對獨立 Blazor WebAssembly 應用程式或託管的 Blazor WebAssembly 解決方案中的 Client 應用程式提供 Microsoft.Extensions.Http 的套件參考。
在 Azure 入口網站中,為 Microsoft Graph 資料授與委派的權限 (範圍)†,應用程式應該能夠代表使用者存取。 針對本文中的範例,應用程式註冊應包含可讀取使用者資料的委派權限(API permissions 中的 Microsoft.Graph>User.Read 範圍,類型:委派)。
User.Read 範圍允許使用者登入應用程式,並且允許應用程式讀取已登入使用者的設定檔和公司資訊。 如需詳細資訊,請參閱 Microsoft 身分識別平臺 的許可權和同意概觀和 Microsoft Graph 許可權概觀。
†權限和範圍代表相同的事項,在安全性文件和 Azure 入口網站中交換使用。 除非本文指的是 Azure 入口網站,否則在提及 Graph 權限時,本文會使用 範圍/ 範圍。
範圍不區分大小寫,因此 User.Read 與 user.read 相同。 請隨意使用任一格式,但建議在應用程式碼之間選擇一致的格式。
在 Azure 入口網站的應用程式註冊中新增 Microsoft Graph API 範圍之後,請將下列應用程式設定組態新增至 wwwroot/appsettings.json 檔案,其中包括 Graph 基底 URL 以及 Microsoft Graph 版本和範圍。 在下列範例中,會針對本文後續幾節中的範例指定 User.Read 範圍。 範圍不區分大小寫。
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
在上述範例中,{VERSION} 預留位置是 Microsoft 圖形 API 的版本 (例如:v1.0)。
以下是應用程式的完整 wwwroot/appsettings.json 組態檔範例,該應用程式會使用 ME-ID 作為其識別提供者,其中已針對 Microsoft Graph 指定讀取使用者資料 (user.read 範圍) :
{
"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"
]
}
}
在上述範例中,{TENANT ID} 預留位置是目錄 (租用戶) 識別碼,而 {CLIENT ID} 預留位置是應用程式 (用戶端) 識別碼。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
在 GraphAuthorizationMessageHandler 檔案中建立下列 Program 類別和專案設定,以使用 圖形 API。 基底 URL 和範圍會透過設定提供給處理常式。
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" ]);
}
}
授權 URL 需要有後置斜線 (/)。 上述程式碼會從應用程式設定建置下列授權 URL,如果缺少應用程式設定,則會預設為下列授權 URL:https://graph.microsoft.com/v1.0/。
在 Program 檔案中,為 圖形 API 設定名為 HttpClient 的項目:
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>();
在前述範例中,GraphAuthorizationMessageHandlerDelegatingHandler 已註冊為 AddHttpMessageHandler 的暫時性服務。 建議對 IHttpClientFactory 進行暫時性註冊,以管理其本身的 DI 範圍。 如需詳細資訊,請參閱以下資源:
基底位址需要有後置斜線 (/)。 在上述程式碼中,string.Join 的第三個引數為 string.Empty,以確保後置斜線存在:https://graph.microsoft.com/v1.0/。
使用名為 HttpClient 的元件呼叫 圖形 API
UserInfo.cs 類別會透過 JsonPropertyNameAttribute 屬性和ME-ID 所使用的 JSON 名稱來指定必要的使用者設定檔屬性。 下列範例會設定使用者行動電話和辦公室位置的屬性。
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; }
}
在下列 UserData 元件中,會建立 HttpClient,供 圖形 API 發出要求以取得使用者的設定檔資料。
me 資源 (me) 會新增至圖形 API 要求的基底 URL 與版本。 Graph 傳回的 JSON 資料會還原序列化為 UserInfo 類別屬性。 在下列範例中,會取得行動電話號碼。 如果您想要的話,可以新增類似的程式碼,以包含使用者的 ME-ID 設定檔辦公室位置 (userInfo.OfficeLocation)。 如果存取權杖要求失敗,則會將使用者重新導向,以登入應用程式並取得新的存取權杖。
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();
}
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
提示
若要將使用者新增至應用程式,請參閱將使用者指派給應用程式註冊(有無應用程式角色)一節。
下列順序描述 圖形 API 範圍的新使用者流程:
- 新使用者第一次登入應用程式。
- 使用者同意在 Azure 同意 UI 中使用應用程式。
- 使用者會第一次存取要求 圖形 API 資料的元件頁面。
- 使用者會被重新導向至 Azure 同意 UI,以同意 圖形 API 範圍。
- 系統會傳回 圖形 API 使用者資料。
如果您希望在首次登入時進行範圍佈建(即同意 圖形 API 範圍),請在 Program 檔案中,於 MSAL 驗證將這些範圍指定為預設存取權杖範圍:
+ 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);
+ }
});
重要
如需了解上述程式碼為何使用 來新增範圍,而非使用 ,請參閱 與 一節。
對應用程式進行上述變更時,使用者流程會採用下列順序:
- 新使用者第一次登入應用程式。
- 使用者同意在 Azure 同意 UI 中使用應用程式和 圖形 API 範圍。
- 使用者會第一次存取要求 圖形 API 資料的元件頁面。
- 系統會傳回 圖形 API 使用者資料。
在本機使用圖形 API 進行測試時,我們建議針對每個測試使用新的 InPrivate/incognito 瀏覽器工作模式,以防止徘徊的 cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
使用已命名的 HttpClient 自訂使用者宣告
在以下範例中,應用程式會根據使用者 ME-ID 使用者個人資料設定檔中的資料,為該使用者建立行動電話號碼和辦公室所在地宣告。 應用程式必須在 ME-ID 中設定 User.Read 圖形 API 範圍。 要在 ME-ID 中測試使用者帳戶,必須輸入行動電話號碼和辦公室位置,這些資料可透過 Azure 入口網站新增至使用者設定檔。
如果您尚未依照本文先前的指引將 UserInfo 類別新增至應用程式,請新增下列類別,並使用 ME-ID 所使用的 JsonPropertyNameAttribute 屬性和 JSON 名稱指定必要的使用者設定檔屬性。 下列範例會設定使用者行動電話和辦公室位置的屬性。
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; }
}
在下列自訂使用者帳戶處理站中:
- 為了方便起見,系統包含了 ILogger(
logger),以便您在CreateUserAsync方法中記錄資訊或錯誤。 - 如果發生 AccessTokenNotAvailableException,則會將使用者重新導向至身份提供者以登入使用者帳戶。 要求存取權杖失敗時,可以採取其他或不同的動作。 例如,應用程式可以記錄 AccessTokenNotAvailableException 並建立支援單,以供進一步調查。
- 架構的 RemoteUserAccount 代表使用者帳戶。 如果應用程式需要擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將自訂使用者帳戶類別替換為 RemoteUserAccount。
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;
}
}
MSAL 驗證已設定為使用自訂使用者帳戶處理站。 首先,確認 Program 檔案使用 Microsoft.AspNetCore.Components.WebAssembly.Authentication 命名空間:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
在 Program 檔案中,尋找對 AddMsalAuthentication 擴充方法的呼叫。 將程式碼更新為以下內容,其中包含對 AddAccountClaimsPrincipalFactory 的呼叫,以加入搭配 CustomAccountFactory 的帳戶宣告主體處理站。
如果應用程式會使用擴充 RemoteUserAccount 的自訂使用者帳戶類別,請在下列程式碼中將您應用程式的自訂使用者帳戶類別替換為 RemoteUserAccount。
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
上述範例適用於將 ME-ID 驗證與 MSAL 搭配使用的應用程式。 OIDC 和 API 驗證也有類似的模式。 如需詳細資訊,請參閱 ASP.NET Core Blazor WebAssembly 其他安全性案例 一文中 使用承載宣告自訂使用者 一節的範例。
您可以在使用者向 ME-ID 進行驗證後,使用下列 UserClaims 元件審視使用者的宣告:
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;
}
}
在 NavMenu 元件中新增元件頁面的連結 (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>
在本機使用圖形 API 進行測試時,我們建議針對每個測試使用新的 InPrivate/incognito 瀏覽器工作模式,以防止徘徊的 cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式。
無論是否使用應用程式角色,將使用者指派給應用程式註冊
您可以在 Azure 入口網站中使用下列步驟,將使用者新增至應用程式註冊,並將角色指派給使用者。
若要新增使用者,請從 Azure 入口網站的 ME-ID 區域中選取 [使用者]:
- 選取 [新增使用者]>[建立新使用者]。
- 使用建立使用者範本。
- 在 Identity 區域中提供使用者的資訊。
- 您可以產生初始密碼,或指派使用者第一次登入後要變更的初始密碼。 如果您使用入口網站所產生的密碼,請立即記下該密碼。
- 選取 [建立] 以建立使用者。 [建立新使用者] 介面關閉時,請選取 [重新整理],以更新使用者清單並顯示新的使用者。
- 如需本文中的範例,請從使用者清單中選取其名稱、選取 [屬性],以及編輯連絡資訊以提供行動電話號碼,將行動電話號碼指派給新使用者。
若要在沒有應用程式角色的情況下將使用者指派給應用程式:
- 在 Azure 入口網站的 ME-ID 區域中,開啟企業應用程式。
- 從清單中選取應用程式。
- 選取 使用者及群組。
- 選取 [新增使用者/群組]。
- 選取使用者。
- 選取 [指派] 按鈕。
若要在具有應用程式角色的情況下將使用者指派給應用程式:
- 遵循具有 Microsoft Entra ID 群組和角色的 ASP.NET Core Blazor WebAssembly 中的指導,將角色新增至 Azure 入口網站中的應用程式註冊。
- 在 Azure 入口網站的 ME-ID 區域中,開啟企業應用程式。
- 從清單中選取應用程式。
- 選取 使用者及群組。
- 選取 [新增使用者/群組]。
- 選取使用者,然後選取其角色以存取應用程式。 將多個角色指派給使用者,方法是重複將使用者新增至應用程式的程序,直到為使用者指派所有角色為止。 具有多個角色的使用者,在該應用程式的使用者與群組使用者清單中,會依每個指派的角色各列出一次。
- 選取 [指派] 按鈕。
DefaultAccessTokenScopes 與 AdditionalScopesToConsent
本文中的範例會使用 DefaultAccessTokenScopes 佈建 圖形 API 範圍,而不是使用 AdditionalScopesToConsent。
不會使用 AdditionalScopesToConsent,因為使用者第一次透過 Azure 同意 UI 使用 MSAL 登入應用程式時,無法為使用者佈建 圖形 API 範圍。 當使用者第一次嘗試使用 Graph SDK 存取 圖形 API 時,他們遇到例外狀況:
Microsoft.Graph.Models.ODataErrors.ODataError: Access token is empty.
在使用者透過 DefaultAccessTokenScopes 佈建 圖形 API 範圍之後,應用程式就可以使用 AdditionalScopesToConsent 來進行後續使用者登入。 不過,變更應用程式程式碼對於需要定期新增具有委派 Graph 範圍的新使用者,或將新的委派 圖形 API 範圍新增至應用程式的生產應用程式來說並無意義。
先前有關在使用者第一次登入應用程式時,如何佈建 圖形 API 存取範圍的討論僅適用於:
- 採用 Graph SDK 的應用程式。
- 使用已命名 HttpClient 存取 圖形 API 的應用程式,會在使用者首次登入應用程式時要求其同意 Graph 權限範圍。
使用未要求使用者在首次登入時同意 Graph 範圍權限的具名 HttpClient 時,使用者在首次透過預先設定的具名 HttpClient 的 DelegatingHandler要求存取 圖形 API 時,會被重新導向至 Azure 同意介面,以同意 圖形 API 範圍權限。 當一開始未以名為 HttpClient 的方法取得 Graph 範圍權限的同意時,應用程式既不會呼叫 DefaultAccessTokenScopes,也不會呼叫 AdditionalScopesToConsent。 如需詳細資訊,請參閱本文中已命名的 HttpClient 涵蓋範圍。
託管的 Blazor WebAssembly 解決方案
本文中的範例與下列用法有關:直接從獨立的 Blazor WebAssembly 應用程式,或直接從託管 Blazor WebAssemblysolution 的 Client 應用程式,使用 Graph SDK 或搭配 圖形 API 的具名 HttpClient。 本文未涵蓋另一個案例,即託管解決方案的 Client 應用程式透過 Web API 呼叫解決方案的 Server 應用程式,然後 Server 應用程式使用 Graph SDK/API 呼叫 Microsoft Graph,並將資料傳回至 Client 應用程式。 雖然這是支援的方法,但本文未加以說明。 如果您想要採用此方法:
- 依照從 ASP.NET Core Blazor 應用程式呼叫 Web API 中的指引,透過 Web API 從 Server 應用程式發出對 Client 應用程式的要求 ,並將資料傳回至 Client 應用程式。
- 依照主要 Microsoft Graph 文件中的指引,將 Graph SDK 用於一般 ASP.NET Core 應用程式 (在此案例中為解決方案的 Server 應用程式)。 如果您使用 Blazor WebAssembly 項目範本來建立託管 Blazor WebAssembly 解決方案(ASP.NET Core Hosted/
-h|--hosted),並搭配組織授權(單一組織/SingleOrg或多個組織/MultiOrg)和Microsoft graph 選項 (Microsoft 身分識別平臺>Connected Services>在 Visual Studio 中新增 Microsoft Graph 許可權,或使用 .NET CLI--calls-graph命令dotnet new選項), 解決方案 Server 應用程式設定為從專案範本建立方案時使用 Graph SDK。
其他資源
一般方針
- Microsoft Graph 說明文件
- Microsoft Graph 範例 Blazor WebAssembly 應用程式:此範例示範如何使用 Microsoft Graph .NET SDK 從 Blazor WebAssembly 應用程式存取 Office 365 中的資料。
- 使用 Microsoft Graph 教學課程建置 .NET 應用程式和 Microsoft Graph 範例 ASP.NET Core 應用程式:雖然從用戶端應用程式Blazor WebAssembly 呼叫 Graph 時不會直接套用這些資源,但連結資源中的 ME-ID 應用程式設定和 Microsoft Graph 編碼實務與獨立 Blazor WebAssembly 應用程式有關,應將其視為通用最佳做法予以參考。
- Microsoft Graph 說明文件
- Microsoft Graph 範例 Blazor WebAssembly 應用程式:此範例示範如何使用 Microsoft Graph .NET SDK 從 Blazor WebAssembly 應用程式存取 Office 365 中的資料。
- 使用 Microsoft Graph 教學課程建置 .NET 應用程式和 Microsoft Graph 範例 ASP.NET Core 應用程式:這些資源最適用於託管的Blazor WebAssembly 解決方案,其中,Server 應用程式會設定為代表 Client 應用程式將 Microsoft Graph 視為一般 ASP.NET Core 應用程式來存取。 Client 應用程式會使用 Web API 對 Server 應用程式提出 Graph 資料的要求。 雖然從用戶端應用程式Blazor WebAssembly 呼叫 Graph 時不會直接套用這些資源,但連結資源中的 ME-ID 應用程式設定和 Microsoft Graph 編碼實務與獨立 Blazor WebAssembly 應用程式有關,應將其視為通用最佳做法予以參考。