在Blazor InteractiveAuto模式下如何保留Microsoft Graph API SDK认证状态?
Blazor WASM 切换后 Microsoft 认证失效及 Microsoft Graph 集成解决方案
Blazor Server 和 WebAssembly(WASM)的认证机制存在本质差异:Server 依赖服务器端会话管理认证状态,而 WASM 是在客户端本地存储令牌并自主管理认证流程。你原有的 Server 端认证配置无法直接适配 WASM,需针对客户端和服务器端(若为托管式 WASM)分别调整配置,同时解决认证状态跨渲染模式的持久化问题。
一、客户端(WASM)核心配置
安装依赖包
确保客户端项目已安装以下 NuGet 包:Microsoft.Identity.Web.UIMicrosoft.GraphMicrosoft.AspNetCore.Components.WebAssembly.Authentication
Program.cs 配置认证与 Graph SDK
替换原有认证配置,改为适配 WASM 的 MSAL 认证,并集成 Microsoft Graph:var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.RootComponents.Add<HeadOutlet>("head::after"); // 配置 MSAL 认证,绑定 Azure AD 配置 builder.Services.AddMsalAuthentication(options => { builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); // 添加 Microsoft Graph 所需的默认作用域 options.ProviderOptions.DefaultAccessTokenScopes.Add("User.Read"); // 配置令牌缓存到本地存储,实现认证状态持久化 options.ProviderOptions.Cache.CacheLocation = Microsoft.Identity.Client.CacheLocation.LocalStorage; // 启用 Cookie 存储认证状态,支持 SSR 到 WASM 的状态传递 options.ProviderOptions.Cache.StoreAuthStateInCookie = true; }); // 注册 Microsoft Graph SDK 服务 builder.Services.AddMicrosoftGraph(options => { options.Scopes = new[] { "User.Read", "Mail.Read" }; // 根据业务需求调整作用域 }); // 替换默认认证状态提供者,支持跨渲染模式的状态持久化 builder.Services.AddScoped<AuthenticationStateProvider, PersistingRevalidatingAuthenticationStateProvider>(); await builder.Build().RunAsync();客户端配置文件
在wwwroot/appsettings.json中添加 Azure AD 配置:{ "AzureAd": { "Authority": "https://login.microsoftonline.com/你的租户ID", "ClientId": "你的客户端ID", "ValidateAuthority": true } }
二、服务器端(托管式 WASM)适配配置
若你的项目是托管式 WASM(Server 作为宿主),需调整服务器端配置以支持客户端令牌验证,并保留服务器端调用 Graph 的能力:
Program.cs 调整认证配置
var builder = WebApplication.CreateBuilder(args); // 添加 Razor 组件服务,启用双渲染模式 builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); // 配置认证:同时支持 Cookie(Server 端)和 Bearer(WASM 客户端) builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(options => { options.Cookie.Name = ".BlazorWasmAuth"; }) .AddMicrosoftIdentityWebApp(builder.Configuration, "AzureAd") .EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read" }) .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) .AddDistributedTokenCaches(); // 配置授权策略 builder.Services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy; }); // 添加 Microsoft Identity UI 支持登录/注销页面 builder.Services.AddControllersWithViews().AddMicrosoftIdentityUI(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAntiforgery(); app.UseAuthentication(); app.UseAuthorization(); // 映射 Razor 组件,启用双渲染模式 app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(typeof(Client._Imports).Assembly); // 映射控制器路由(用于登录/注销) app.MapControllers(); app.Run();服务器端配置文件
在appsettings.json中完善 Azure AD 和 Graph 配置:{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "你的租户域名", "TenantId": "你的租户ID", "ClientId": "你的客户端ID", "ClientSecret": "你的客户端密钥", "CallbackPath": "/signin-oidc" }, "DownstreamApi": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": "User.Read Mail.Read" } }
三、关键注意事项
- Azure AD 应用注册配置:确保重定向 URI 包含 WASM 客户端的回调地址(如
https://localhost:5001/authentication/login-callback),并已授予所需 Graph 作用域的管理员同意。 - 认证状态持久化:通过
LocalStorage存储令牌确保客户端刷新页面后认证状态不丢失,StoreAuthStateInCookie配置则解决 SSR 切换到 WASM 交互模式时的状态传递问题。 - 组件中使用 Graph:直接注入
GraphServiceClient即可调用 API,无需手动管理令牌,SDK 会自动从认证状态中获取有效令牌:@inject GraphServiceClient GraphClient @inject AuthenticationStateProvider AuthStateProvider @if (user != null) { <p>当前用户:@user.DisplayName</p> } @code { private User? user; protected override async Task OnInitializedAsync() { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity?.IsAuthenticated == true) { user = await GraphClient.Me.Request().GetAsync(); } } }
内容的提问来源于stack exchange,提问作者Benoit
相关产品推荐
相关产品推荐

