且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

将ASP.Net身份表链接到用户详细信息表

更新时间:2023-12-04 10:27:10

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

Your main issue is simply that UserManager has no functionality to include related entities, such as your UserProfile. As a result, you have two options:

  1. 直接使用您的上下文.然后,您只需一个查询就可以将UserProfileApplicationUser实例一起加载到数据库中:

  1. Use your context directly instead. Then you can eagerly load your UserProfile along with the ApplicationUser instance, in just one query to the database:

var user = await _context.Users.Include(x => x.UserProfile).SingleOrDefaultAsync(x => x.UserName ==  model.UserName);

  • 您可以改为显式加载相关的UserProfile.但是,这将导致额外的查询,总共查询两个:一个查询用户,另一个查询相关的个人资料:

  • You can explicitly load the related UserProfile instead. This will result in an extra query, though, for a total of two: one to get the user and one to get the related profile:

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

  • 但是,坦率地说,您根本不应该拥有UserProfile. ASP.NET身份与ASP.NET成员资格不同.对于后者,您必须有一个单独的UserProfile,因为成员资格中的用户"是不可扩展的.在Identity中,用户 是可扩展的,因此,如果要在其上添加其他配置文件信息,只需将其添加到类中即可:

    However, frankly, you should not have UserProfile at all. ASP.NET Identity is not like ASP.NET Membership. With the latter, you had to have a separate UserProfile because the "user" in Membership was not extensible. In Identity, the user is extensible, so if you want additional profile information on it, just add it to the class:

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

    请注意,我也在这里修剪了很多碎屑.覆盖Id然后使其自动实现没有意义.另外,您显然不需要UserProfile中的UserName属性,因为IdentityUser已经具有该属性,这当然意味着您的ApplicationUser也具有它.

    Note that I trimmed a lot of cruft here as well. There's no point in overriding the Id and then leaving it auto-implemented. Additionally, you obviously don't need the UserName property from UserProfile because IdentityUser already has that, which then of course means your ApplicationUser has it as well.

    更新

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

    How the user data is persisted doesn't have to affect whether it can be a claim or not. In other words, you don't have to literally save data as claim in order to access it as claim. Just derive from UserClaimsPrincipalFactory<TUser>, override CreateAsync, and then register it with service collection as scoped.

    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>();