Link ASP.Net 身份 table 到用户详细信息 table

Link ASP.Net Identity table to a user detail table

我正在尝试 link 我的身份用户 table 到我创建的用于跟踪其他用户信息的用户详细信息 table。该用户详细信息 table 称为 UserProfile。

我遇到了这个 link 但它在 .NET Core 2.1 中不起作用:

这是我目前拥有的:

public class ApplicationUser : IdentityUser
{

    [Key]
    public override string Id { get; set; }

    [ForeignKey("Id")]
    public virtual UserProfile UserProfile { get; set; }

}

[Table("UserProfile")]
public class UserProfile
{
    [Key, ForeignKey("User")]
    public string UserId { get; set; } // UserId (Primary key) 
    public string UserName { get; set; } // UserName 
    public string FirstName { get; set; } // FirstName
    public string LastName { get; set; } // LastName

    //[ForeignKey("Id")]
    public virtual ApplicationUser User { get; set; }
}

然而,在我调用的代码的其他地方:

var user = await _userMgr.FindByNameAsync(model.UserName);

并且user.UserProfile为空。

我试过很多数据标注的组合甚至流利api都无济于事

   modelBuilder.Entity<ApplicationUser>()
       .HasOne(c => c.UserProfile)
       .WithOne(t => t.User)
       .HasForeignKey<UserProfile>(b => b.UserId);

我也试过打开延迟加载,但那甚至无法加载 属性。

有谁知道如何在 .Net Core 2.1 中执行此操作?

谢谢

您的主要问题只是 UserManager 没有包含相关实体的功能,例如您的 UserProfile。因此,您有两个选择:

  1. 直接使用您的上下文。然后,您可以在对数据库的一次查询中立即加载 UserProfileApplicationUser 实例:

    var user = await _context.Users.Include(x => x.UserProfile).SingleOrDefaultAsync(x => x.UserName ==  model.UserName);
    
  2. 您可以显式加载相关的 UserProfile。但是,这将导致额外的查询,总共有两个:一个用于获取用户,一个用于获取相关配置文件:

    await _context.Entry(user).Reference(x => x.UserProfile).LoadAsync();
    

但是,坦率地说,您根本不应该 UserProfile。 ASP.NET 身份不同于 ASP.NET 会员资格。对于后者,您必须有一个单独的 UserProfile,因为 Membership 中的 "user" 不可扩展。在 Identity 中,用户 可扩展的,因此如果您想要关于它的其他个人资料信息,只需将其添加到 class:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; } // FirstName
    public string LastName { get; set; } // LastName
}

请注意,我在这里也修剪了很多杂物。覆盖 Id 然后让它自动实现是没有意义的。此外,您显然不需要 UserProfile 中的 UserName 属性 因为 IdentityUser 已经有了,这当然意味着您的 ApplicationUser 也有.

更新

用户数据的保存方式不一定会影响它是否可以声明。换句话说,您不必按字面意义将数据保存为声明即可访问它作为声明。只需从 UserClaimsPrincipalFactory<TUser> 派生,覆盖 CreateAsync,然后将其注册为作用域的服务集合。

public class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public MyClaimsPrincipalFactory(UserManager<TUser> userManager, IOptions<IdentityOptions> optionsAccessor)
        : base(userManager, optionsAccessor)
    {
    }

    public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        var principal = await base.CreateAsync(user);
        ((ClaimsIdentity)principal.Identity).AddClaims(new[]
        {
            new Claim(ClaimTypes.GivenName, user.FirstName),
            new Claim(ClaimTypes.Surname, user.LastName),
            // etc.
        });

        return principal;
    }
}

然后在 ConfigureServices:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyClaimsPrincipalFactory>();