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

Blazor Server应用Azure AD登录事件处理及DI容器访问问题

实现方案说明

你选择的OnTokenValidated事件是完全符合需求的正确触发点,该事件仅会在用户首次登录、Azure AD令牌校验通过时触发,不会重复执行,刚好适配首次拉取用户数据的场景。

如何在事件处理程序中访问DI容器

你不需要用[FromServices]或者构造函数注入,TokenValidatedContext自带的HttpContext属性就包含当前请求的服务作用域容器,直接从中获取服务即可,这也是官方推荐的认证事件中访问DI的标准方式,避免直接使用根容器导致的服务生命周期混乱问题。

示例代码如下:

using Microsoft.Extensions.DependencyInjection; // 要引用这个命名空间才能用GetRequiredService方法

private async Task OnTokenValidatedFuncAsync(TokenValidatedContext context)
{
    var userName = context.Principal.Identity.Name;
    // 从当前请求的服务作用域获取所需服务,替换成你自己的服务接口即可
    var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
    var cacheService = context.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();

    // 从数据库/API拉取用户数据
    var userData = await userService.GetUserDataAsync(userName);
    var userId = context.Principal.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier);

    // 缓存逻辑二选一即可:
    // 方案1:小体量数据直接追加到用户声明中,后续Blazor中直接通过AuthenticationState读取
    var extraClaims = new List<System.Security.Claims.Claim>
    {
        new("DisplayName", userData.DisplayName),
        new("Department", userData.Department)
    };
    context.Principal.AddIdentity(new System.Security.Claims.ClaimsIdentity(extraClaims));

    // 方案2:大体量数据存入缓存,用用户唯一标识作为Key,后续请求直接按Key读取
    await cacheService.SetStringAsync($"UserData_{userId}", System.Text.Json.JsonSerializer.Serialize(userData), new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24)
    });

    await Task.CompletedTask.ConfigureAwait(false);
}

备选纯Blazor生命周期实现方案

如果你不想修改认证中间件配置,也可以完全在Blazor的生命周期中实现,所有服务都可以直接注入,不需要处理DI访问问题:

  1. 先注册一个Scoped生命周期的用户状态容器
// Program.cs 中注册
builder.Services.AddScoped<UserCurrentState>();

// UserCurrentState类定义
public class UserCurrentState
{
    public UserData MyData { get; set; }
}
  1. 在根组件App.razor的初始化生命周期中执行拉取逻辑
// App.razor代码后置
[Inject] private AuthenticationStateProvider AuthProvider { get; set; }
[Inject] private IUserService UserService { get; set; }
[Inject] private UserCurrentState CurrentState { get; set; }

protected override async Task OnInitializedAsync()
{
    var authState = await AuthProvider.GetAuthenticationStateAsync();
    if (authState.User.Identity.IsAuthenticated && CurrentState.MyData == null)
    {
        var userId = authState.User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier);
        CurrentState.MyData = await UserService.GetUserDataAsync(userId);
    }
}

后续任意Blazor组件中注入UserCurrentState即可直接读取用户数据,每个用户会话只会执行一次拉取逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 20:06:04