Microsoft ASP.NET标识 - 具有相同名称的多个用户

Com*_*ity 8 c# asp.net authentication forms-authentication asp.net-identity

我正在尝试一些充满异国情调的东西我相信并且我遇到了一些问题,我希望可以在StackOverflow上的用户帮助下解决这些问题.

故事

我正在编写和申请,需要认证和注册.我选择使用Microsoft.AspNet.Identity.我过去没有经常使用它,所以不要在这个决定上评判我.

上面提到的框架包含一个users表,它包含所有注册用户.

我已经创建了一个示例图片来展示应用程序的工作方式.

在此输入图像描述

该应用程序包含3个不同的组件:

  1. 后端(WebAPI).
  2. 客户(直接使用WebAPI).
  3. 最终用户(使用移动应用程序 - iOS).

所以,我确实有一个客户可以注册的后端.每个成员有一个唯一用户,所以这里没问题.客户是这里的公司,最终用户是公司的客户.

你可能已经看到了这个问题,完全有可能User 1是一个人,Customer 1但也是Customer 2.

现在,客户可以邀请会员使用移动应用程序.当客户这样做时,最终用户确实会收到一封电子邮件,其中包含自己激活的链接.

现在,只要您的用户是独一无二的,这一切都正常,但我确实有一个用户,这是一个Customer 1Customer 2.两个客户都可以邀请同一个用户,用户需要注册2次,每次一个Customer.

问题

Microsoft.AspNet.Identity框架中,用户应该是唯一的,根据我的情况,我无法管理.

这个问题

是否可以添加额外的参数以IdentityUser确保用户是唯一的?

我已经做了什么

  1. 创建一个继承自的自定义类,IdentityUser其中包含一个应用程序ID:

    public class AppServerUser : IdentityUser
    {
        #region Properties
    
        /// <summary>
        ///     Gets or sets the id of the member that this user belongs to.
        /// </summary>
        public int MemberId { get; set; }
    
        #endregion
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 改变了我的IDbContext相应:

    public class AppServerContext : IdentityDbContext<AppServerUser>, IDbContext { }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用框架的已修改调用.

    IUserStore<IdentityUser> -> IUserStore<AppServerUser>
    UserManager<IdentityUser>(_userStore) -> UserManager<AppServerUser>(_userStore);
    
    Run Code Online (Sandbox Code Playgroud)

    _userStore 是偏离类型的 IUserStore<AppServerUser>

但是,当我使用已经使用的用户名注册用户时,我仍然会收到一条错误消息,指出已经使用了用户名:

var result = await userManager.CreateAsync(new AppServerUser {UserName = "testing"}, "testing");
Run Code Online (Sandbox Code Playgroud)

我相信的是一个解决方案

我相信我需要改变UserManager但我不确定.我希望这里有人对框架有足够的了解,可以帮助我,因为它确实阻碍了我们的应用程序开发.

如果不可能,我也想知道,也许你可以指出另一个允许我这样做的框架.

注意:我不想自己编写完整的用户管理,因为这将重新启动方向盘.

小智 2

首先,我理解您的想法背后的想法,因此我将开始解释“为什么”您无法创建多个具有相同名称的用户。

同名用户名: 您现在遇到的问题与IdentityDbContext有关。如您所见(https://aspnetidentity.codeplex.com/SourceControl/latest#src/Microsoft.AspNet.Identity.EntityFramework/IdentityDbContext.cs),identityDbContext设置有关唯一用户和角色的规则,首先是模型创建:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        if (modelBuilder == null)
        {
            throw new ArgumentNullException("modelBuilder");
        }

        // Needed to ensure subclasses share the same table
        var user = modelBuilder.Entity<TUser>()
            .ToTable("AspNetUsers");
        user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        user.Property(u => u.UserName)
            .IsRequired()
            .HasMaxLength(256)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true }));

        // CONSIDER: u.Email is Required if set on options?
        user.Property(u => u.Email).HasMaxLength(256);

        modelBuilder.Entity<TUserRole>()
            .HasKey(r => new { r.UserId, r.RoleId })
            .ToTable("AspNetUserRoles");

        modelBuilder.Entity<TUserLogin>()
            .HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId })
            .ToTable("AspNetUserLogins");

        modelBuilder.Entity<TUserClaim>()
            .ToTable("AspNetUserClaims");

        var role = modelBuilder.Entity<TRole>()
            .ToTable("AspNetRoles");
        role.Property(r => r.Name)
            .IsRequired()
            .HasMaxLength(256)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true }));
        role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
    }
Run Code Online (Sandbox Code Playgroud)

其次是验证实体:

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
        IDictionary<object, object> items)
    {
        if (entityEntry != null && entityEntry.State == EntityState.Added)
        {
            var errors = new List<DbValidationError>();
            var user = entityEntry.Entity as TUser;
            //check for uniqueness of user name and email
            if (user != null)
            {
                if (Users.Any(u => String.Equals(u.UserName, user.UserName)))
                {
                    errors.Add(new DbValidationError("User",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateUserName, user.UserName)));
                }
                if (RequireUniqueEmail && Users.Any(u => String.Equals(u.Email, user.Email)))
                {
                    errors.Add(new DbValidationError("User",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateEmail, user.Email)));
                }
            }
            else
            {
                var role = entityEntry.Entity as TRole;
                //check for uniqueness of role name
                if (role != null && Roles.Any(r => String.Equals(r.Name, role.Name)))
                {
                    errors.Add(new DbValidationError("Role",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.RoleAlreadyExists, role.Name)));
                }
            }
            if (errors.Any())
            {
                return new DbEntityValidationResult(entityEntry, errors);
            }
        }
        return base.ValidateEntity(entityEntry, items);
    }
}
Run Code Online (Sandbox Code Playgroud)

提示: 要轻松解决此问题,您可以在当前拥有的 ApplicationDbContext 上重写这两个方法来克服此验证

警告: 如果没有该验证,您现在可以使用具有相同名称的多个用户,但您必须实施规则来阻止您在同一客户中使用相同的用户名创建用户。您可以做的是将其添加到验证中。

希望帮助有价值:) 干杯!