You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server集成Microsoft Entra ID:用户数据获取与服务注册问题

解决Blazor Server注册请求级用户服务的错误问题

错误原因

你遇到的InvalidOperationException是因为没有在DI容器中注册IUser接口对应的实现类,同时缺少结合Microsoft Graph调用逻辑的服务封装。

解决步骤

1. 定义用户接口与实现类

在Data文件夹下创建IUser.cs和UserService.cs:

IUser.cs

namespace BlazorServerAppAzureAD.Data;

public interface IUser
{
    // 获取当前登录用户信息
    Task<CurrentUser> GetCurrentUserAsync();
    // 获取其他用户列表(可按需调整参数)
    Task<List<OtherUser>> GetOtherUsersAsync();
}

// 封装当前用户数据结构
public class CurrentUser
{
    public string DisplayName { get; set; }
    public string Id { get; set; }
    public string Email { get; set; }
}

// 封装其他用户数据结构
public class OtherUser
{
    public string DisplayName { get; set; }
    public string Id { get; set; }
    public string Mail { get; set; }
}

UserService.cs

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Graph;
using System.Security.Claims;

namespace BlazorServerAppAzureAD.Data;

public class UserService : IUser
{
    private readonly GraphServiceClient _graphClient;
    private readonly AuthenticationStateProvider _authStateProvider;

    public UserService(GraphServiceClient graphClient, AuthenticationStateProvider authStateProvider)
    {
        _graphClient = graphClient;
        _authStateProvider = authStateProvider;
    }

    public async Task<CurrentUser> GetCurrentUserAsync()
    {
        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        
        // 调用Graph获取当前用户详细信息
        var graphUser = await _graphClient.Me.Request()
            .Select(u => new { u.Id, u.DisplayName, u.Mail })
            .GetAsync();
        
        return new CurrentUser
        {
            Id = graphUser.Id,
            DisplayName = graphUser.DisplayName,
            Email = graphUser.Mail ?? user.FindFirstValue(ClaimTypes.Email)
        };
    }

    public async Task<List<OtherUser>> GetOtherUsersAsync()
    {
        // 调用Graph获取其他用户列表,按需限制数量
        var users = await _graphClient.Users.Request()
            .Select(u => new { u.Id, u.DisplayName, u.Mail })
            .Top(50)
            .GetAsync();
        
        return users.Select(u => new OtherUser
        {
            Id = u.Id,
            DisplayName = u.DisplayName,
            Mail = u.Mail
        }).ToList();
    }
}

2. 在Program.cs中注册服务

确保已配置Microsoft Entra ID认证和Graph服务,再添加请求级服务注册:

using BlazorServerAppAzureAD.Data;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;

var builder = WebApplication.CreateBuilder(args);

// 配置Microsoft Entra ID认证
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(new[] { "https://graph.microsoft.com/User.Read.All" })
    .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
    .AddInMemoryTokenCaches();

builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});

// 注册请求级(Scoped)的IUser服务
builder.Services.AddScoped<IUser, UserService>();

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();

var app = builder.Build();

// 中间件配置
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

3. 在页面中注入使用

在Index.razor中注入IUser服务,替代CascadingParameter:

@page "/"
@inject BlazorServerAppAzureAD.Data.IUser UserService

<h1>当前登录用户信息</h1>

@if (currentUser != null)
{
    <p>姓名: @currentUser.DisplayName</p>
    <p>UID: @currentUser.Id</p>
    <p>邮箱: @currentUser.Email</p>
}

<h2>其他用户列表</h2>

@if (otherUsers != null)
{
    <ul>
        @foreach (var user in otherUsers)
        {
            <li>@user.DisplayName - @user.Mail</li>
        }
    </ul>
}

@code {
    private CurrentUser currentUser;
    private List<OtherUser> otherUsers;

    protected override async Task OnInitializedAsync()
    {
        currentUser = await UserService.GetCurrentUserAsync();
        otherUsers = await UserService.GetOtherUsersAsync();
    }
}

4. 验证配置

  • 确保appsettings.json中的AzureAd和MicrosoftGraph配置正确:
{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "你的租户域名",
    "TenantId": "你的租户ID",
    "ClientId": "你的应用ID",
    "CallbackPath": "/signin-oidc"
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "User.Read.All"
  }
}
  • 确认Entra ID中应用的User.Read.All权限已获取管理员同意。

关键注意点

  • Blazor Server中Scoped服务对应请求级生命周期,符合需求。
  • 必须通过AuthenticationStateProvider获取用户认证状态,不能直接依赖HttpContext。
  • 调用Graph时用Select方法指定需要的字段,减少数据传输量。

内容的提问来源于stack exchange,提问作者sada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:56:05