将 SimpleMembership 迁移到 Identity 2.0 [英] Migrating SimpleMembership to Identity 2.0

查看:18
本文介绍了将 SimpleMembership 迁移到 Identity 2.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题已经演变,所以我更新了标题.

This question has evolved so I've updated the title.

这是原来的标题:Identity 2 UserManager.Find 抛出无效的对象名称'dbo.ApplicationUser'"错误

This was the original title: Identity 2 UserManager.Find throws "Invalid object name 'dbo.ApplicationUser'" error

我正在从 SimpleMembership 转换为 Identity 2.我已经运行了转换脚本并重构了各种文件以供 Identity 使用.我可以构建和运行应用程序,但是当尝试登录时,会抛出无效的对象名称'dbo.ApplicationUser'"错误var user = UserManager.Find(vM.UserName, vM.Password);

I'm converting from SimpleMembership to Identity 2. I've ran the conversion script and refactored the various files for Identity use. I can build and run the app but when attempt to login an "Invalid object name 'dbo.ApplicationUser'" error is thrown on var user = UserManager.Find(vM.UserName, vM.Password);

账户管理员:

  [RequireHttps]
  [Authorize]
  public class AccountController : Controller
  {
    private readonly IUserService _userService;

    public UserManager<ApplicationUser> UserManager { get; private set; }

    public AccountController() 
    : this(new UserService(), new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDb()))) { } 

    public AccountController(IUserService userService, UserManager<ApplicationUser> userManager)
    { _userService = userService; UserManager = userManager; }

    // GET: /Account/Login
    [AllowAnonymous]
    public ActionResult Login() { return View(); }

    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginVm vM)
    { 
      if (ModelState.IsValid) 
      { 
        var user = UserManager.Find(vM.UserName, vM.Password);
        if (user != null)
        { 
          FormsAuthentication.SetAuthCookie(user.UserName, false);
          return RedirectToAction("Index", "Home");
        }
      } 
      ModelState.AddModelError("", "The user name or password provided is incorrect.");

      return View(vM);
    }

应用用户:

  public class ApplicationUser : IdentityUser
  { 
    [StringLength(15)]
    public new string UserName { get; set; }
    public int AcId { get; set; }
    public int LcId { get; set; }
    public string ConfirmationToken { get; set; }
    public bool IsConfirmed { get; set; }
    public string PasswordResetToken { get; set; }
  }

数据库上下文:

  public class MyDb : IdentityDbContext<ApplicationUser> // DbContext  
  {
    public MyDb() : base("MyApplicaiton") { }

    // public virtual DbSet<UserProfiles> Users { get; set; }
    public virtual DbSet<MyTable> MyTables { get; set; } // properties marked virtual for Mocking override
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

      modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
      modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
      modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
    }
  }

为什么用户管理器尝试访问 dbo.[ApplicationUser](不存在)而不是 dbo.[AspNetUsers]?

Why is user manager trying to access dbo.[ApplicationUser] (which doesn't exist) rather than dbo.[AspNetUsers]?

更新 1:我已降级到 Microsoft.AspNet.Identity.EntityFramework 1.0 和 Microsoft.AspNet.Identity.Core 1.0,现在在调用 UserManager.Find 时出现无效的对象名称 'dbo.IdentityUser'"错误.

UPDATE 1: I downgraded to Microsoft.AspNet.Identity.EntityFramework 1.0 and Microsoft.AspNet.Identity.Core 1.0 and I now get a "Invalid object name 'dbo.IdentityUser'" error when UserManager.Find is called.

更新 2:

我升级回 Identity 2.0,只是想看看备份和删除数据库会发生什么,然后先用代码重新生成它(启用迁移、更新数据库).

I upgraded back to Identity 2.0 and just to see what would happen backed up and deleted the database and regenerated it with code first (enable-migrations, update-database).

而不是添加以下默认身份表:
AspNetRoles
AspNetClaims
AspNetUserLogins
AspNetUserRoles
AspNet 用户

Instead of adding the default Identity tables of:
AspNetRoles
AspNetClaims
AspNetUserLogins
AspNetUserRoles
AspNetUsers

它添加了这些表格:
dbo.ApplicationUser
dbo.IdentityRole
dbo.IdentityUserClaim
dbo.IdentityUserLogin
dbo.IdentityUserRole

It added these tables:
dbo.ApplicationUser
dbo.IdentityRole
dbo.IdentityUserClaim
dbo.IdentityUserLogin
dbo.IdentityUserRole

这可以解释为什么它正在寻找 ApplicationUser.我的配置强制使用这些名称而不是标准身份名称的原因是什么?我可能可以将我的迁移脚本更改为这些名称,但最终我会得到非标准的表名,这只会导致未来的混乱.如何配置获取默认身份表名称?

Which would explain why it is looking for ApplicationUser. What is it about my configuration that is forcing those names instead of the standard Identity names? I probably could change my migration script to those names but then I would end up with non-standard table names which would only lead to confusion going forward. How do I configure things to get the default Identity table names?

推荐答案

表名的问题在于 OnModelCreating 的覆盖.我对 .Entity<...>().HasKey 的调用正在调用这些表名.有关覆盖的更多信息,请参阅 Olav Nyb0 在此处的回答:Asp.net 身份验证错误.我已将 OnModelCreating 更新为:

The problem with the table names was with the override of OnModelCreating. My calls to .Entity<...>().HasKey were invoking those table names. For more on the override see Olav Nyb0's answer here: Asp.net Identity Validation Error. I've updated the OnModelCreating to:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);
  modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}

我的 ApplicationUser 和迁移脚本以 Identity 1.0 为模型,我需要为 Identity 2.0 更新它们.

My ApplicationUser and migration script were modeled on Identity 1.0 and I needed to update them for Identity 2.0.

应用用户:

  public class ApplicationUser : IdentityUser
  { 
    public int AcId { get; set; }
    public int LcId { get; set; }
   }

这是我最终针对我的 SimpleMembership 数据库运行的迁移脚本.有点偏离最初的问题,但我将其包含在此处,希望能节省其他人我花在解决问题上的时间.

Here's the migration script I ended up with that I run against my SimpleMembership database. A bit off the original question but I include it here to hopefully save someone else the hours I spent figuring it out.

    /****** Object: Table [dbo].[AspNetRoles] Script Date: 4/29/14 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

IF OBJECT_ID('dbo.AspNetUserRoles', 'U') IS NOT NULL
    DROP TABLE [dbo].[AspNetUserRoles]
GO
--IF OBJECT_ID('dbo.AspNetUserLogins', 'U') IS NOT NULL
--  DROP TABLE [dbo].[AspNetUserLogins]
--GO
IF OBJECT_ID('dbo.AspNetUserClaims', 'U') IS NOT NULL
    DROP TABLE [dbo].[AspNetUserClaims]
GO
IF OBJECT_ID('dbo.AspNetRoles', 'U') IS NOT NULL
    DROP TABLE [dbo].[AspNetRoles]
GO
IF OBJECT_ID('dbo.AspNetUsers', 'U') IS NOT NULL
    DROP TABLE [dbo].[AspNetUsers]
GO

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]                                      NVARCHAR (128) NOT NULL,
    [UserName]                                NVARCHAR (15) NULL,
    [AcId]                                    INT            NOT NULL,
    [LcId]                                    INT            NOT NULL,
    [Email]                                   NVARCHAR (256) NULL,
    [EmailConfirmed]                          BIT            DEFAULT ((0)) NULL,
    [PasswordHash]                            NVARCHAR (MAX) NULL,
    [SecurityStamp]                           NVARCHAR (MAX) NULL,  
    [PhoneNumber]                             NVARCHAR (MAX) NULL,
    [PhoneNumberConfirmed]                    BIT            DEFAULT ((0)) NULL,
    [TwoFactorEnabled]                        BIT            DEFAULT ((0)) NULL,
    [LockoutEndDateUtc]                       DATETIME       NULL,
    [Lockoutenabled]                          BIT            DEFAULT ((0)) NULL,
    [AccessFailedCount]                       INT            DEFAULT ((0)) NOT NULL,
    [Discriminator]                           NVARCHAR (128) NOT NULL,
    [CreateDate]                              DATETIME       NULL,
    [ConfirmationToken]                       NVARCHAR (128) NULL,
    [IsConfirmed]                             BIT            DEFAULT ((0)) NULL,
    [LastPasswordFailureDate]                 DATETIME       NULL,
    [PasswordFailuresSinceLastSuccess]        INT            DEFAULT ((0)) NULL,
    [PasswordChangedDate]                     DATETIME       NULL,
    [PasswordVerificationToken]               NVARCHAR (128) NULL,
    [PasswordVerificationTokenExpirationDate] DATETIME       NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[AspNetRoles] (
    [Id]   NVARCHAR (128) NOT NULL,
    [Name] NVARCHAR (256) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetRoles] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[AspNetUserRoles] (
    [UserId] NVARCHAR (128) NOT NULL,
    [RoleId] NVARCHAR (128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
    CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_RoleId]
    ON [dbo].[AspNetUserRoles]([RoleId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_UserId]
    ON [dbo].[AspNetUserRoles]([UserId] ASC);
GO
CREATE TABLE [dbo].[AspNetUserLogins] (
    [UserId]        NVARCHAR (128) NOT NULL,
    [LoginProvider] NVARCHAR (128) NOT NULL,
    [ProviderKey]   NVARCHAR (128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserLogins] PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [ProviderKey] ASC),
    CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_UserId]
    ON [dbo].[AspNetUserLogins]([UserId] ASC);
GO

CREATE TABLE [dbo].[AspNetUserClaims] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [ClaimType]  NVARCHAR (MAX) NULL,
    [ClaimValue] NVARCHAR (MAX) NULL,
    [UserId]    NVARCHAR (128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserClaims] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_User_Id] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_User_Id]
    ON [dbo].[AspNetUserClaims]([UserId] ASC);
GO

INSERT INTO AspNetUsers(Id, UserName, BaId, OfcId, PasswordHash, SecurityStamp, Discriminator,
CreateDate, ConfirmationToken, IsConfirmed, LastPasswordFailureDate, PasswordFailuresSinceLastSuccess,
PasswordChangedDate, PasswordVerificationToken, PasswordVerificationTokenExpirationDate)
SELECT UserProfile.UserId, UserProfile.UserName, UserProfile.BaId, UserProfile.OfcId,
webpages_Membership.Password, webpages_Membership.PasswordSalt, 'User', CreateDate, 
ConfirmationToken, IsConfirmed, LastPasswordFailureDate, PasswordFailuresSinceLastSuccess,
PasswordChangedDate, PasswordVerificationToken, PasswordVerificationTokenExpirationDate
FROM UserProfile
LEFT OUTER JOIN webpages_Membership ON UserProfile.UserId = webpages_Membership.UserId
GO

INSERT INTO AspNetRoles(Id, Name)
SELECT RoleId, RoleName
FROM webpages_Roles
GO

INSERT INTO AspNetUserRoles(UserId, RoleId)
SELECT UserId, RoleId
FROM webpages_UsersInRoles
GO

IF OBJECT_ID('dbo.webpages_OAuthMembership', 'U') IS NOT NULL
    DROP TABLE [dbo].[webpages_OAuthMembership]
GO

IF OBJECT_ID('dbo.webpages_UsersInRoles', 'U') IS NOT NULL
    DROP TABLE [dbo].[webpages_UsersInRoles]
GO
IF OBJECT_ID('dbo.webpages_Roles', 'U') IS NOT NULL
    DROP TABLE [dbo].[webpages_Roles]
GO
IF OBJECT_ID('dbo.UserProfile', 'U') IS NOT NULL
    DROP TABLE [dbo].[UserProfile]
GO
IF OBJECT_ID('dbo.webpages_Membership', 'U') IS NOT NULL
    DROP TABLE [dbo].[webpages_Membership]
GO

--INSERT INTO AspNetUserLogins(UserId, LoginProvider, ProviderKey)
--SELECT UserId, Provider, ProviderUserId
--FROM webpages_OAuthMembership
--GO

我没有使用社交登录,因此将 Insert into AspNetUserLogins 注释掉(您确实需要创建表,因为 Identity 2.0 需要它).

I'm not using Social logins hence the commenting out of Insert into AspNetUserLogins (you do need to create the table though since Identity 2.0 is expecting it).

Identity 2.0 AspNetUsers 表默认具有以下字段:
[编号]
[电子邮件]
[电子邮件确认]
[密码哈希]
[安全印章]
[电话号码]
[已确认电话号码]
[启用双因素]
[LockoutEndDateUtc]
[LockoutEnabled]
[访问失败次数]
[用户名]

The Identity 2.0 AspNetUsers Table has these fields by default:
[Id]
[Email]
[EmailConfirmed]
[PasswordHash]
[SecurityStamp]
[PhoneNumber]
[PhoneNumberConfirmed]
[TwoFactorEnabled]
[LockoutEndDateUtc]
[LockoutEnabled]
[AccessFailedCount]
[UserName]

我仍在试验中,请根据您的最佳判断来确定需要从 pages_Membership 表迁移的内容.此时我可以登录了.

I'm still experimenting, use your best judgment as to what you need to migrate from the webpages_Membership table. At this point I can login though.

更新:

在我的 ApplicationUser 中,我重写了 UserName 以缩短该字段.不要这样做,它会导致身份验证错误.您可以控制迁移脚本中的字段长度.我已经删除了 OP 中的覆盖.有关更多信息,请参阅 User.IsInRole 失败.

In my ApplicationUser I had overridden the UserName to shorten the field. DO NOT do this, it will cause an authentication error. You can control the field length in the migration script. I've removed the override in the OP. For more see User.IsInRole failing.

应用用户:

  public class ApplicationUser : IdentityUser
  { 
    // [StringLength(15)]   // do not override UserName, will cause authentication error.
    // public new string UserName { get; set; }
    public int AcId { get; set; }
    public int LcId { get; set; }
    // public string ConfirmationToken { get; set; }  // Depends on your app if you need to migrate these fields
    // public bool IsConfirmed { get; set; }
    // public string PasswordResetToken { get; set; }
  }

这篇关于将 SimpleMembership 迁移到 Identity 2.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆