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

Blazor:如何在服务中获取IdentityUser.Id?

在服务中获取IdentityUser.Id的实现方案

可以使用AuthenticationStateProvider在服务中获取IdentityUser.Id,因为用户的GUID ID是固定不变的,即便该组件不跟踪状态变化,也不会影响获取这个固定值,完全满足你的日志范围和审计追踪需求。

核心实现步骤

  • 向服务中注入AuthenticationStateProvider
  • 调用其GetAuthenticationStateAsync()方法异步获取用户认证状态
  • 从用户的Claims中提取ID(通常对应ClaimTypes.NameIdentifier类型,需与你的Identity配置一致)
  • 注意判断用户是否已认证,避免未登录场景下的空引用问题

针对两种用途的具体实现

1. 为日志添加用户ID范围

在服务方法中获取用户ID后,使用ILogger.BeginScope()创建日志范围,后续该范围内的所有日志都会自动带上用户ID,方便筛选:

public class BusinessService
{
    private readonly AuthenticationStateProvider _authProvider;
    private readonly ILogger<BusinessService> _logger;

    public BusinessService(AuthenticationStateProvider authProvider, ILogger<BusinessService> logger)
    {
        _authProvider = authProvider;
        _logger = logger;
    }

    public async Task ProcessDataAsync()
    {
        var authState = await _authProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity?.IsAuthenticated ?? false)
        {
            var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
            
            // 开启用户ID日志范围
            using (_logger.BeginScope("UserId:{UserId}", userId))
            {
                _logger.LogInformation("开始处理数据");
                // 执行业务逻辑
                _logger.LogInformation("数据处理完成");
            }
        }
    }
}

如果是Razor页面场景,也可以在页面基类中统一处理日志范围,避免每个页面重复代码。

2. EF实体审计追踪

可以通过EF的SaveChangesInterceptor统一处理实体的创建/更新人赋值,无需在每个服务方法中重复操作:

第一步:定义审计接口

public interface IAuditableEntity
{
    string CreatedById { get; set; }
    DateTime CreatedAt { get; set; }
    string UpdatedById { get; set; }
    DateTime UpdatedAt { get; set; }
}

第二步:实现审计拦截器

public class AuditInterceptor : SaveChangesInterceptor
{
    private readonly AuthenticationStateProvider _authProvider;

    public AuditInterceptor(AuthenticationStateProvider authProvider)
    {
        _authProvider = authProvider;
    }

    public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData, 
        InterceptionResult<int> result, 
        CancellationToken cancellationToken = default)
    {
        var authState = await _authProvider.GetAuthenticationStateAsync();
        var userId = authState.User.FindFirstValue(ClaimTypes.NameIdentifier);

        if (eventData.Context != null && !string.IsNullOrEmpty(userId))
        {
            var now = DateTime.UtcNow;
            // 处理新增实体
            foreach (var entry in eventData.Context.ChangeTracker.Entries<IAuditableEntity>()
                .Where(e => e.State == EntityState.Added))
            {
                entry.Entity.CreatedById = userId;
                entry.Entity.CreatedAt = now;
                entry.Entity.UpdatedById = userId;
                entry.Entity.UpdatedAt = now;
            }

            // 处理更新实体
            foreach (var entry in eventData.Context.ChangeTracker.Entries<IAuditableEntity>()
                .Where(e => e.State == EntityState.Modified))
            {
                entry.Entity.UpdatedById = userId;
                entry.Entity.UpdatedAt = now;
                // 避免覆盖创建时间
                entry.Property(nameof(IAuditableEntity.CreatedById)).IsModified = false;
                entry.Property(nameof(IAuditableEntity.CreatedAt)).IsModified = false;
            }
        }

        return await base.SavingChangesAsync(eventData, result, cancellationToken);
    }
}

第三步:注册拦截器到EF上下文

在Program.cs中添加:

builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
    options.AddInterceptors(new AuditInterceptor(builder.Services.BuildServiceProvider().GetRequiredService<AuthenticationStateProvider>()));
});

注意事项

  • 确保用户已登录:在获取用户ID前必须检查user.Identity.IsAuthenticated,避免未登录时的空引用异常
  • ClaimType一致性:确认你的Identity配置中,用户ID对应的Claim类型是ClaimTypes.NameIdentifier,如果是自定义类型,需替换为对应的字符串
  • 异步处理:GetAuthenticationStateAsync是异步方法,服务中调用时需使用await,避免阻塞线程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:05:28