基于Azure AD认证的.NET Core应用用户关联记录追踪方案咨询
针对Azure AD认证.NET Core应用的操作追踪解决方案
核心结论
你需要创建极简本地用户表(仅存Azure AD用户核心标识和基础信息),登录时同步用户信息,业务表直接关联用户的Azure AD ObjectId即可,不需要额外元表。
具体实现步骤
创建本地用户表
只保留必要字段,避免冗余:public class AppUser { // Azure AD用户唯一标识,作为主键 public string ObjectId { get; set; } = string.Empty; // 用户显示名称 public string DisplayName { get; set; } = string.Empty; // 用户邮箱 public string Email { get; set; } = string.Empty; // 最后同步Azure AD信息的时间 public DateTime LastSyncTime { get; set; } }在EF Core DbContext中配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AppUser>() .HasKey(u => u.ObjectId); }登录时同步Azure AD用户信息
在Azure AD OpenID Connect配置中,利用OnTokenValidated事件同步用户数据:services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { // 你的Azure AD配置 Configuration.Bind("AzureAd", options); options.Events = new OpenIdConnectEvents { OnTokenValidated = async context => { // 从Claims中获取Azure AD用户核心信息 var objectId = context.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var displayName = context.Principal.FindFirstValue(ClaimTypes.Name); var email = context.Principal.FindFirstValue(ClaimTypes.Email); if (string.IsNullOrEmpty(objectId)) return; // 获取DbContext实例 var dbContext = context.HttpContext.RequestServices.GetRequiredService<AppDbContext>(); var existingUser = await dbContext.AppUsers.FindAsync(objectId); if (existingUser == null) { // 新增用户 dbContext.AppUsers.Add(new AppUser { ObjectId = objectId, DisplayName = displayName ?? string.Empty, Email = email ?? string.Empty, LastSyncTime = DateTime.UtcNow }); } else { // 同步更新变更的信息(比如名称、邮箱) bool hasChanged = false; if (existingUser.DisplayName != displayName) { existingUser.DisplayName = displayName ?? string.Empty; hasChanged = true; } if (existingUser.Email != email) { existingUser.Email = email ?? string.Empty; hasChanged = true; } if (hasChanged) { existingUser.LastSyncTime = DateTime.UtcNow; } } await dbContext.SaveChangesAsync(); } }; });业务表添加追踪字段
给需要追踪的业务实体添加以下字段:public class BusinessEntity { // 业务主键 public int Id { get; set; } // 其他业务字段... // 追踪字段 public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } public string CreatedByObjectId { get; set; } = string.Empty; public string UpdatedByObjectId { get; set; } = string.Empty; // 关联本地用户表(可选,用于查询时联表获取用户信息) public AppUser CreatedBy { get; set; } = null!; public AppUser UpdatedBy { get; set; } = null!; }在DbContext中配置外键:
modelBuilder.Entity<BusinessEntity>() .HasOne(e => e.CreatedBy) .WithMany() .HasForeignKey(e => e.CreatedByObjectId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity<BusinessEntity>() .HasOne(e => e.UpdatedBy) .WithMany() .HasForeignKey(e => e.UpdatedByObjectId) .OnDelete(DeleteBehavior.Restrict);自动填充追踪字段
重载EF Core的SaveChangesAsync方法,自动设置创建/更新时间和操作用户,避免重复代码:public class AppDbContext : DbContext { private readonly IHttpContextAccessor _httpContextAccessor; public AppDbContext(DbContextOptions<AppDbContext> options, IHttpContextAccessor httpContextAccessor) : base(options) { _httpContextAccessor = httpContextAccessor; } public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { var currentUserId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier); var now = DateTime.UtcNow; foreach (var entry in ChangeTracker.Entries()) { if (entry.Entity is BusinessEntity entity) { switch (entry.State) { case EntityState.Added: entity.CreatedAt = now; entity.UpdatedAt = now; entity.CreatedByObjectId = currentUserId ?? string.Empty; entity.UpdatedByObjectId = currentUserId ?? string.Empty; break; case EntityState.Modified: entity.UpdatedAt = now; entity.UpdatedByObjectId = currentUserId ?? string.Empty; // 禁止修改创建时间和创建人 entry.Property(nameof(entity.CreatedAt)).IsModified = false; entry.Property(nameof(entity.CreatedByObjectId)).IsModified = false; break; } } } return await base.SaveChangesAsync(cancellationToken); } }
为什么不用IdentityUser?
纯Azure AD认证场景下,ASP.NET Core Identity的AspNetUserLogins表是用来关联本地用户账户和第三方登录的,但你不需要本地账户体系,Identity整套框架会带来不必要的冗余(比如AspNetUsers、AspNetRoles等表)。自己建极简用户表更轻量,完全适配你的需求。
内容的提问来源于stack exchange,提问作者oknsyl
相关产品推荐
相关产品推荐

