【问题标题】:ASP.NET Identity my schemaASP.NET 标识我的架构
【发布时间】:2017-06-10 15:19:42
【问题描述】:

我已经有数据库并且需要添加 ASP.NET 标识。我的 AspNetUser 类:

public partial class AspNetUser
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public AspNetUser()
    {
        AspNetUserClaims = new HashSet<AspNetUserClaim>();
        AspNetUserLogins = new HashSet<AspNetUserLogin>();
        AspNetRoles = new HashSet<AspNetRole>();
    }

    public string Id { get; set; }

    public string UserName { get; set; }

    public string PasswordHash { get; set; }

    public string SecurityStamp { get; set; }

    public int? CompanyId { get; set; }

    public string FullName { get; set; }

    [Required]
    [StringLength(128)]
    public string Discriminator { get; set; }

    public string SMSnumber { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
}

然后是我的 ApplicationDbContext 上下文:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("MainContext", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

连接字符串:

<add name="MainContext" connectionString="data source=server;initial catalog=3md_maindb_remote;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />

ApplicationUser 类:

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

    public int CompanyId { get; set; }
    public string SMSnumber { get; set; }
    public string FullName { get; set; }
}

应用程序用户管理器:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = false
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = false,
            RequireLowercase = false,
            RequireUppercase = false,
        };

        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;

        // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
        // You can write your own provider and plug it in here.
        manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is {0}"
        });
        manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}

当我尝试登录时,出现错误:

异常详细信息:System.Data.SqlClient.SqlException:无效列 名称“电子邮件”。列名“EmailConfirmed”无效。列无效 名称“电话号码”。列名“PhoneNumberConfirmed”无效。 列名“TwoFactorEnabled”无效。列名无效 'LockoutEndDateUtc'。列名“LockoutEnabled”无效。无效的 列名“AccessFailedCount”。

另外,我有 MainContext:

public partial class MainContext : DbContext
{
    public MainContext()
        : base("name=MainContext")
    {
    }

    public virtual DbSet<AspNetRole> AspNetRoles { get; set; }
    public virtual DbSet<AspNetUserClaim> AspNetUserClaims { get; set; }
    public virtual DbSet<AspNetUserLogin> AspNetUserLogins { get; set; }
    public virtual DbSet<AspNetUser> AspNetUsers { get; set; }

据我了解,我需要使用 MainContext 而不是 ApplicationDbContext (with my schema) ,但不明白如何...

【问题讨论】:

  • 为什么需要使用 MainContext 而不是 ApplicationDbContext?反之亦然。使用 ApplicationDbContext 作为标识。
  • 现在我使用 ApplicationDbContext,但它需要 'Email' 列...
  • 您不必使用该列,它只需要存在即可。身份框架使用用户名或电子邮件。这取决于 ApplicationUserManager.Create 中的 RequireUniqueEmail 设置。如果为 false,则使用用户名,否则使用电子邮件。我不会担心电子邮件列。
  • @RuardvanElburg,但我已经有数据库,无法编辑...
  • 只是好奇,为什么不能添加列?

标签: c# dbcontext asp.net-identity-2


【解决方案1】:

您可以在同一个数据库上使用多个上下文。开箱即用的身份上下文设置为可用。如果你不需要改变它,那就不要。仅将身份表用于身份。

您不需要在身份上下文中定义表。只需添加 ApplicationDbContext。您可以使用与 MainContext 相同的连接字符串:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("name=MainContext")
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

您真的不应该将所有表都添加到 IdentityContext 中,因为那不是它们应该在的地方。虽然这些表可能在同一个数据库中,但这两个上下文彼此无关。

在 MainContext 中保留您自己的表,并且除了可以将 IdentityUser 引用到 MainContext.User 的列(仅值,而不是数据库引用)之外,不要与上下文相关联。从 MainContext 中删除 AspNet... 表。

您不能使用 AspNetUser 类。所以你也可以删除它。请改用 ApplicationUser 类。要克服缺少字段的问题,请使用以下方法:

public class ApplicationUser : IdentityUser
{
    [NotMapped]
    public override bool EmailConfirmed { get => base.EmailConfirmed; set => base.EmailConfirmed = value; }

    // etc.
}

这将忽略缺失的列。请记住,这些属性存在于代码中并且具有默认值。虽然我认为您的代码实际上不会依赖这些属性。

如果 MainContext 给您带来麻烦,您可以使用相同的实体对象创建自己的上下文。即使您使用单独的程序集,您也可以在同一个数据库上创建多个上下文,仅包括使用过的表。

【讨论】:

  • 现在我得到属性“电子邮件”不是“应用程序用户”类型上的声明属性。使用 Ignore 方法或 NotMappedAttribute 数据注释验证该属性是否已从模型中显式排除。确保它是有效的原始属性
  • Email 的问题在于 Identity 2 依赖于它。另请参阅:stackoverflow.com/questions/23055411/… 这意味着您必须自己实现大部分 Identity2 功能。我建议您让您的客户决定:添加一个列并使其工作或重新实现标识 2 以使其工作。
  • 另一种方法是将身份表移动到另一个数据库。
【解决方案2】:

因为ApplicationDbContext 是开箱即用的DbContext。您的项目中不需要任何其他DbContext。因此,只需在您的项目中完全删除MainContext 类,并将您自己的实体放入ApplicationDbContext 类中。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("MainContext", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
    // put your extra entities here like this.
    public IDbSet<MyEntity> MyEntites { get; set;}

    // don't put Identity related entities like AspNetRoles. Since already added
}  

【讨论】:

    猜你喜欢
    • 2014-07-11
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    相关资源
    最近更新 更多