简体   繁体   English

使用 Identity 2.0 数据库对 ASP.NET Core 1.0 应用程序进行身份验证

[英]Use a Identity 2.0 Database to Authenticate a ASP.NET Core 1.0 application

I am trying to a create a new ASP.NET Core 1.0 web application and I want it to use the Authentication tables that I already have set up.我正在尝试创建一个新的 ASP.NET Core 1.0 Web 应用程序,我希望它使用我已经设置的身份验证表。 These tables were originally created by a ASP.NET 4.6 web application that used Microsoft.ASPNet.Identity.EntityFramework 2.2.0这些表最初是由使用 Microsoft.ASPNet.Identity.EntityFramework 2.2.0 的 ASP.NET 4.6 Web 应用程序创建的

It looks like things have change in Microsoft.AspNetCore.Identity.EntityFrameworkCore because the new Core 1.0 application throws this error when trying to log in:看起来 Microsoft.AspNetCore.Identity.EntityFrameworkCore 中的事情发生了变化,因为新的 Core 1.0 应用程序在尝试登录时会抛出此错误:

A database operation failed while processing the request.处理请求时数据库操作失败。

SqlException: Invalid column name 'NormalizedUserName'. SqlException: 无效的列名“NormalizedUserName”。 Invalid column name 'ConcurrencyStamp'.无效的列名“ConcurrencyStamp”。 Invalid column name 'LockoutEnd'.无效的列名“LockoutEnd”。 Invalid column name 'NormalizedEmail'.无效的列名“NormalizedEmail”。 Invalid column name 'NormalizedUserName'.无效的列名“NormalizedUserName”。

The project.json is straight out of the box and looks like this: project.json 是开箱即用的,如下所示:

"dependencies": {
"Microsoft.NETCore.App": {
  "version": "1.0.0",
  "type": "platform"
},
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Razor.Tools": {
  "version": "1.0.0-preview2-final",
  "type": "build"
},
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer.Design": {
  "version": "1.0.0",
  "type": "build"
},
"Microsoft.EntityFrameworkCore.Tools": {
  "version": "1.0.0-preview2-final",
  "type": "build"
},
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
  "version": "1.0.0-preview2-final",
  "type": "build"
},
"Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
  "version": "1.0.0-preview2-final",
  "type": "build"
}

}, },

Also, I have not changed my ApplicationDbContext, but I have seen some posts about making changes to resolve this issue in that class另外,我没有更改我的 ApplicationDbContext,但我看到了一些关于在该类中进行更改以解决此问题的帖子

This SQL migration script got me over the above hurdle:这个 SQL 迁移脚本让我克服了上述障碍:

Alter Table ASPNETROLES
ADD
 ConcurrencyStamp varchar(255) null,               
 NormalizedName varchar(255) null

 Drop Table AspNetUserTokens

 CREATE TABLE [AspNetUserTokens] (
    [UserId]        NVARCHAR (450) NOT NULL,
    [LoginProvider] NVARCHAR (450) NOT NULL,
    [Name]          NVARCHAR (450) NOT NULL,
    [Value]         NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_AspNetUserTokens]
 PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [Name] ASC)
)

Alter Table AspNetUsers
 Add
 ConcurrencyStamp varchar(255) null,
 LockoutEnd DateTime null,
 NormalizedEmail varchar(255) null,
 NormalizedUserName varchar(255) null

Drop Table [AspNetRoleClaims]

CREATE TABLE [AspNetRoleClaims] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [ClaimType]  NVARCHAR (MAX) NULL,
    [ClaimValue] NVARCHAR (MAX) NULL,
    [RoleId]     NVARCHAR (128) NOT NULL,
    CONSTRAINT [PK_AspNetRoleClaims]
 PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId]
 FOREIGN KEY ([RoleId])
  REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE
)


GO
CREATE NONCLUSTERED INDEX [IX_AspNetRoleClaims_RoleId]
    ON [AspNetRoleClaims]([RoleId] ASC)

Alter Table AspNetUserLogins
   Add  ProviderDisplayName varchar(255) null

There's not been a ton of guidance from Microsoft over how to migrate the database but this fixed the above issue for me.微软并没有就如何迁移数据库提供大量指导,但这为我解决了上述问题。

There's a package available to do this.有一个包可以做到这一点。 It literally is for this exact purpose.从字面上看,它就是为了这个确切的目的。 It is part of Microsoft's codebase, and appears to have been updated recently for Core 2.1.它是 Microsoft 代码库的一部分,最近似乎已针对 Core 2.1 进行了更新。

A compatibility layer for sharing identity databases between Microsoft.AspNet.Identity.EntityFramework and Microsoft.AspNetCore.Identity.EntityFrameworkCore.用于在 Microsoft.AspNet.Identity.EntityFramework 和 Microsoft.AspNetCore.Identity.EntityFrameworkCore 之间共享身份数据库的兼容层。

https://www.nuget.org/packages/Microsoft.AspNet.Identity.AspNetCoreCompat/ https://www.nuget.org/packages/Microsoft.AspNet.Identity.AspNetCoreCompat/

https://github.com/aspnet/Identity/tree/master/src/AspNetCoreCompat https://github.com/aspnet/Identity/tree/master/src/AspNetCoreCompat

It handles the 'differences' between the two schemas with methods like this:它使用以下方法处理两个模式之间的“差异”:

    /// <summary>
    ///     Normalized email
    /// </summary>
    public string NormalizedEmail {
        get
        {
            return Email.ToUpperInvariant();
        }
        set { }
    }

    /// <summary>
    ///     Concurrency stamp
    /// </summary>
    public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

I cannot find any real documentation, but I've done the following and it seems to be working ok:我找不到任何真正的文档,但我已经完成了以下操作并且它似乎工作正常:

  • You install the compatibility package in your OLD website (.NET 4.6)您在旧网站 (.NET 4.6) 中安装兼容包
  • You must change ALL references to IdentityRole , IdentityUser , IdentityDbContext etc. to be the classes from the compatibility package.您必须将所有对IdentityRoleIdentityUserIdentityDbContext等的引用更改为兼容包中的类。

     using Compat = Microsoft.AspNet.Identity.CoreCompat; // update to use the compatibility class public class ApplicationDbContext : Compat.IdentityDbContext<ApplicationUser> // change all instances, such as this Compat.IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
  • You have to upgrade your database to the new format (basically adding a few columns and changing some data types).您必须将数据库升级到新格式(基本上是添加几列并更改一些数据类型)。 This is the trickiest stage!这是最棘手的阶段! You're going to want to do this on a staging environment for sure.您肯定希望在登台环境中执行此操作。 I'm using Azure so I just cloned the DB.我正在使用 Azure,所以我只是克隆了数据库。

  • On GitHub I found some migrations scripts by @samnpathdr called Migration.zip .在 GitHub 上,我发现了一些由@samnpathdr编写的迁移脚本,称为Migration.zip There are several scripts to be run one by one.有几个脚本要一一运行。 I'd recommend running each command one at a time to make sure it all runs.我建议一次运行一个命令以确保它全部运行。
  • Currently there's one table in his script that is custom to his implementation (AspNetUserRolePermissions) so delete references to that.目前,他的脚本中有一个表是针对他的实现 (AspNetUserRolePermissions) 定制的,因此请删除对该表的引用。
  • If you have any other tables referencing the AspNetUsers table, you must drop constraints, update the datatypes and add the constraints back.如果您有任何其他表引用AspNetUsers表,则必须删除约束、更新数据类型并重新添加约束。 For example I have a Notes table which is linked to a AspNetUser so I needed to run ALTER TABLE UserProfileNote ALTER COLUMN AspNetUsersId nvarchar(450) NOT NULL;例如,我有一个链接到AspNetUserNotes表,所以我需要运行ALTER TABLE UserProfileNote ALTER COLUMN AspNetUsersId nvarchar(450) NOT NULL; (after removing constraints). (删除约束后)。 Script the constraints first!首先编写约束脚本!
  • Be careful if you have any 'auto migrations' enabled for Core because personally I wouldn't trust them after this kind of change.如果您为 Core 启用了任何“自动迁移”,请小心,因为我个人在这种更改后不会信任它们。 You should reset to a baseline, or not do EF migrations at all.您应该重置为基线,或者根本不进行 EF 迁移。

https://github.com/aspnet/Docs/issues/6425 https://github.com/aspnet/Docs/issues/6425

I manually wrote a migration from the old to the new Identity and the application works with both old and new users.我手动编写了从旧Identity到新Identity的迁移,该应用程序适用于新老用户。 Here's the migration if you want to save yourselves some manual work:如果您想为自己节省一些手动工作,请执行以下迁移:

public partial class Identity : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<string>(
            name: "NormalizedName",
            table: "AspNetRoles",
            type: "nvarchar(256)",
            maxLength: 256,
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "ConcurrencyStamp",
            table: "AspNetRoles",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.RenameColumn(
            name: "LockoutEndDateUtc",
            table: "AspNetUsers",
            newName: "LockoutEnd");

        migrationBuilder.AddColumn<string>(
            name: "ConcurrencyStamp",
            table: "AspNetUsers",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "NormalizedEmail",
            table: "AspNetUsers",
            type: "nvarchar(256)",
            maxLength: 256,
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "NormalizedUsername",
            table: "AspNetUsers",
            type: "nvarchar(256)",
            maxLength: 256,
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "ProviderDisplayName",
            table: "AspNetUserLogins",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.CreateTable(
            name: "AspNetRoleClaims",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                RoleId = table.Column<string>(type: "nvarchar(128)", nullable: false),
                ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
                ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
                table.ForeignKey(
                    name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
                    column: x => x.RoleId,
                    principalTable: "AspNetRoles",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
            });

        migrationBuilder.CreateTable(
            name: "AspNetUserTokens",
            columns: table => new
            {
                UserId = table.Column<string>(type: "nvarchar(128)", nullable: false),
                LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
                Name = table.Column<string>(type: "nvarchar(450)", nullable: false),
                Value = table.Column<string>(type: "nvarchar(max)", nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
                table.ForeignKey(
                    name: "FK_AspNetUserTokens_AspNetUsers_UserId",
                    column: x => x.UserId,
                    principalTable: "AspNetUsers",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "ConcurrencyStamp",
            table: "AspNetRoles");

        migrationBuilder.DropColumn(
            name: "NormalizedName",
            table: "AspNetRoles");

        migrationBuilder.RenameColumn(
            name: "LockoutEnd",
            table: "AspNetUsers",
            newName: "LockoutEndDateUtc");

        migrationBuilder.DropColumn(
            name: "ConcurrencyStamp",
            table: "AspNetUsers");

        migrationBuilder.DropColumn(
            name: "NormalizedEmail",
            table: "AspNetUsers");

        migrationBuilder.DropColumn(
            name: "NormalizedUsername",
            table: "AspNetUsers");

        migrationBuilder.DropColumn(
            name: "ProviderDisplayName",
            table: "AspNetUserLogins");

        migrationBuilder.DropTable("AspNetRoleClaims");

        migrationBuilder.DropTable("AspNetUserTokens");
    }
}

Also keep in mind that is one way migration.还要记住,这是一种迁移方式。 To be able still use old solution you could force .net core to use old password hashing algo为了仍然能够使用旧的解决方案,您可以强制 .net 核心使用旧密码散列算法

services.Configure<PasswordHasherOptions>(options => options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在ASP.NET Core 2.0中更新身份 - Updating Identity in ASP.NET Core 2.0 不能在 ASP.NET 核心中使用我的 MySql 数据库和身份 - cant use my MySql database in ASP.NET Core with Identity Identity Server 4(2.0)不读取Asp.Net核心标识cookie - Identity Server 4 (2.0) not reading Asp.Net Core Identity cookies 带有ASP.NET CORE 1.0的Identity Server 3身份验证/授权 - Identity Server 3 Authentication/Authorization, with ASP.NET CORE 1.0 ASP.NET Core 1.0升级到ConfigureServices中的ASP.NET Core 2.0升级身份验证-如何在Core 2.0中使用字段? - ASP.NET Core 1.0 upgrade to ASP.NET Core 2.0 Upgrade Authentication in ConfigureServices - How do I use Fields in Core 2.0? ASP.NET Core 2.0:在没有控制器的情况下验证路由 - ASP.NET Core 2.0: Authenticate a route without a controller ASP.NET Core 2.0中的应用程序变量 - Application Variables in ASP.NET Core 2.0 ASP.NET Core 2.0 Identity添加新模型-表到数据库 - ASP.NET Core 2.0 Identity add new model - table to the Database Asp.net Core Identity 2.0 Google注销 - Asp.net Core Identity 2.0 Google Logout Asp.net核心2.0 Angular模板:添加身份和身份验证 - Asp.net core 2.0 Angular template: add identity and authentication
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM