既存 Web サイトを SQL メンバーシップから ASP.NET Identity に移行する

作成者 : Rick AndersonSuhas Joshi

このチュートリアルでは、SQL メンバーシップを使用して作成されたユーザーとロールのデータを含む既存の Web アプリケーションを新しい ASP.NET ID システムに移行する手順について説明します。 この方法では、既存のデータベース スキーマを、ASP.NET ID に必要なスキーマに変更し、古いクラスまたは新しいクラスにフックします。 このアプローチを採用すると、データベースが移行されると、今後の ID の更新が簡単に処理されます。

このチュートリアルでは、Visual Studio 2010 を使用して作成された Web アプリケーション テンプレート (Web Forms) を使用して、ユーザーとロールのデータを作成します。 次に、SQL スクリプトを使用して、既存のデータベースを ID システムで必要なテーブルに移行します。 次に、必要な NuGet パッケージをインストールし、メンバーシップ管理に ID システムを使用する新しいアカウント管理ページを追加します。 移行のテストとして、SQL メンバーシップを使用して作成されたユーザーはログインでき、新しいユーザーは登録できる必要があります。 完全なサンプルは、こちらでご覧いただけます。 「 ASP.NET メンバーシップから ASP.NET ID への移行」も参照してください。

はじめに

SQL メンバーシップを使用したアプリケーションの作成

  1. SQL メンバーシップを使用し、ユーザーとロールのデータを持つ既存のアプリケーションから始める必要があります。 この記事では、Visual Studio 2010 で Web アプリケーションを作成します。

    Visual Studio 2010 での Web アプリケーションの作成のスクリーンショット。

  2. ASP.NET 構成ツールを使用して、 oldAdminUser と oldUser の 2 人のユーザーを作成 します。

    A S P のスクリーンショット。2 人のユーザーを作成するための N E T 構成ツール。

    すべてのセキュリティを管理するための Web サイト管理ツールのスクリーンショット。

  3. 管理 という名前のロールを作成し、そのロールのユーザーとして 'oldAdminUser' を追加します。

    そのロールでユーザーとして作成された管理 ロールのスクリーンショット。

  4. Default.aspx を使用してサイトの管理 セクションを作成します。 web.config ファイルで承認タグを設定して、管理ロールのユーザーにのみアクセスできるようにします。 詳細については、こちらを参照してください。 https://www.asp.net/web-forms/tutorials/security/roles/role-based-authorization-cs

    サイトの [管理] セクションのスクリーンショット。

  5. サーバー エクスプローラーでデータベースを表示して、SQL メンバーシップ システムによって作成されたテーブルを理解します。 ユーザー ログイン データはaspnet_Usersテーブルとaspnet_Membership テーブルに格納され、ロール データはaspnet_Roles テーブルに格納されます。 ロールがaspnet_UsersInRoles テーブルに格納されているユーザーに関する情報。 基本的なメンバーシップ管理では、上記の表の情報を ASP.NET ID システムに移植するだけで十分です。

    S Q L メンバーシップ システムによって作成されたテーブルを理解するためにデータベースを表示するサーバー エクスプローラーのスクリーンショット。

Visual Studio 2013 への移行

  1. Visual Studio Express 2013 for Web またはVisual Studio 2013を最新の更新プログラムと共にインストールします。

  2. インストールされているバージョンの Visual Studio で上記のプロジェクトを開きます。 SQL Server Expressがコンピューターにインストールされていない場合は、接続文字列で SQL Express が使用されるため、プロジェクトを開くときにプロンプトが表示されます。 SQL Express のインストールを選択することも、接続文字列を LocalDb に変更することもできます。 この記事では、LocalDb に変更します。

  3. web.configを開き、 から接続文字列を変更します。SQLExpress to (LocalDb)v11.0。 接続文字列から 'User Instance=true' を削除します。

    Visual Studio 2013に移行する接続文字列を変更するスクリーンショット。

  4. [サーバー エクスプローラー] を開き、テーブルのスキーマとデータを確認できることを確認します。

  5. ASP.NET ID システムは、バージョン 4.5 以降のフレームワークで動作します。 アプリケーションを 4.5 以上に再ターゲットします。

    A S P のスクリーンショット。N E T ID システム。

    プロジェクトをビルドして、エラーがないことを確認します。

Nuget パッケージのインストール

  1. ソリューション エクスプローラーで、プロジェクト > [NuGet パッケージの管理] を右クリックします。 検索ボックスに「Asp.net IDENTITY」と入力します。 結果の一覧でパッケージを選択し、[インストール] をクリックします。 [同意する] ボタンをクリックして、使用許諾契約書に同意します。 このパッケージでは、EntityFramework と Microsoft ASP.NET Identity Core の依存関係パッケージがインストールされることに注意してください。 同様に、次のパッケージをインストールします (OAuth ログインを有効にしない場合は、最後の 4 つの OWIN パッケージをスキップします)。

    • Microsoft.AspNet.Identity.Owin

    • Microsoft.Owin.Host.SystemWeb

    • Microsoft.Owin.Security.Facebook

    • Microsoft.Owin.Security.Google

    • Microsoft.Owin.Security.MicrosoftAccount

    • Microsoft.Owin.Security.Twitter

      ソリューション エクスプローラーでの Nuget パッケージのインストールのスクリーンショット。

データベースを新しい ID システムに移行する

次の手順では、既存のデータベースを、ASP.NET ID システムで必要なスキーマに移行します。 これを実現するために、新しいテーブルを作成し、既存のユーザー情報を新しいテーブルに移行するための一連のコマンドを含む SQL スクリプトを実行します。 スクリプト ファイルについては、 こちらを参照してください

このスクリプト ファイルは、このサンプルに固有のものです。 SQL メンバーシップを使用して作成されたテーブルのスキーマをカスタマイズまたは変更する場合は、それに応じてスクリプトを変更する必要があります。

スキーマ移行用の SQL スクリプトを生成する方法

ASP.NET ID クラスが既存のユーザーのデータをすぐに使用できるようにするには、データベース スキーマを ASP.NET Identity に必要なスキーマに移行する必要があります。 これを行うには、新しいテーブルを追加し、それらのテーブルに既存の情報をコピーします。 既定では、ASP.NET Identity は EntityFramework を使用して ID モデル クラスをデータベースにマップし、情報を格納または取得します。 これらのモデル クラスは、ユーザー オブジェクトとロール オブジェクトを定義するコア ID インターフェイスを実装します。 データベース内のテーブルと列は、これらのモデル クラスに基づいています。 Identity v2.1.0 の EntityFramework モデル クラスとそのプロパティは、以下に定義されています

IdentityUser Type IdentityRole IdentityUserRole IdentityUserLogin IdentityUserClaim
Id string Id RoleId ProviderKey Id
ユーザー名 string 名前 UserId UserId ClaimType
PasswordHash string LoginProvider ClaimValue
SecurityStamp string User_id
電子メール string
EmailConfirmed bool
PhoneNumber string
PhoneNumberConfirmed bool
LockoutEnabled bool
LockoutEndDate DateTime
AccessFailedCount INT

これらの各モデルのテーブルと、プロパティに対応する列が必要です。 クラスとテーブル間のマッピングは、 OnModelCreating の メソッドで定義されます IdentityDBContext。 これは、構成の fluent API メソッドと呼ばれ、詳細については 、こちらを参照してください。 クラスの構成は、以下で説明します。

クラス Table 主キー 外部キー
IdentityUser AspnetUsers Id
IdentityRole AspnetRoles Id
IdentityUserRole AspnetUserRole UserId + RoleId User_Id-AspnetUsers> RoleId-AspnetRoles>
IdentityUserLogin AspnetUserLogins ProviderKey + UserId + LoginProvider UserId-AspnetUsers>
IdentityUserClaim AspnetUserClaims Id User_Id-AspnetUsers>

この情報を使用して、新しいテーブルを作成する SQL ステートメントを作成できます。 各ステートメントを個別に記述するか、EntityFramework PowerShell コマンドを使用してスクリプト全体を生成し、必要に応じて編集できます。 これを行うには、VS で [表示] メニューまたは [ツール] メニューからパッケージ マネージャー コンソールを開きます。

  • コマンド "Enable-Migrations" を実行して、EntityFramework の移行を有効にします。
  • C#/VB でデータベースを作成するための初期セットアップ コードを作成するコマンド "Add-migration initial" を実行します。
  • 最後の手順では、モデル クラスに基づいて SQL スクリプトを生成する "Update-Database –Script" コマンドを実行します。

アプリで SQLite を ID データ ストアとして使用する場合、一部のコマンドはサポートされません。 データベース エンジンの制限により、 Alter コマンドは次の例外をスローします。

"System.NotSupportedException: SQLite では、この移行操作はサポートされていません。"

回避策として、データベースで Code First の移行を実行してテーブルを変更します。

このデータベース生成スクリプトは、新しい列を追加してデータをコピーするために追加の変更を加える出発点として使用できます。 この利点は、モデル クラスが将来のバージョンの _MigrationHistory Identity リリースで変更されたときに、EntityFramework によってデータベース スキーマを変更するために使用されるテーブルを生成することです。

SQL メンバーシップのユーザー情報には、ID ユーザー モデル クラスのプロパティに加えて、電子メール、パスワードの試行、最終ログイン日、最終ロックアウト日などのプロパティが含まれています。これは有用な情報であり、ID システムに引き継がれたいと考えています。 これを行うには、ユーザー モデルにプロパティを追加し、データベースのテーブル列にマッピングし直します。 これを行うには、モデルをサブクラス化するクラスを IdentityUser 追加します。 このカスタム クラスにプロパティを追加し、SQL スクリプトを編集して、テーブルの作成時に対応する列を追加できます。 このクラスのコードについては、この記事で詳しく説明します。 新しいプロパティを追加した後にテーブルを AspnetUsers 作成するための SQL スクリプトは、

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]            NVARCHAR (128) NOT NULL,
    [UserName]      NVARCHAR (MAX) NULL,
    [PasswordHash]  NVARCHAR (MAX) NULL,
    [SecurityStamp] NVARCHAR (MAX) NULL,
    [EmailConfirmed]       BIT            NOT NULL,
    [PhoneNumber]          NVARCHAR (MAX) NULL,
    [PhoneNumberConfirmed] BIT            NOT NULL,
    [TwoFactorEnabled]     BIT            NOT NULL,
    [LockoutEndDateUtc]    DATETIME       NULL,
    [LockoutEnabled]       BIT            NOT NULL,
    [AccessFailedCount]    INT            NOT NULL,
    [ApplicationId]                          UNIQUEIDENTIFIER NOT NULL,
    [LegacyPasswordHash]  NVARCHAR (MAX) NULL,
    [LoweredUserName]  NVARCHAR (256)   NOT NULL,
    [MobileAlias]      NVARCHAR (16)    DEFAULT (NULL) NULL,
    [IsAnonymous]      BIT              DEFAULT ((0)) NOT NULL,
    [LastActivityDate] DATETIME2         NOT NULL,
    [MobilePIN]                              NVARCHAR (16)    NULL,
    [Email]                                  NVARCHAR (256)   NULL,
    [LoweredEmail]                           NVARCHAR (256)   NULL,
    [PasswordQuestion]                       NVARCHAR (256)   NULL,
    [PasswordAnswer]                         NVARCHAR (128)   NULL,
    [IsApproved]                             BIT              NOT NULL,
    [IsLockedOut]                            BIT              NOT NULL,
    [CreateDate]                             DATETIME2               NOT NULL,
    [LastLoginDate]                          DATETIME2         NOT NULL,
    [LastPasswordChangedDate]                DATETIME2         NOT NULL,
    [LastLockoutDate]                        DATETIME2         NOT NULL,
    [FailedPasswordAttemptCount]             INT              NOT NULL,
    [FailedPasswordAttemptWindowStart]       DATETIME2         NOT NULL,
    [FailedPasswordAnswerAttemptCount]       INT              NOT NULL,
    [FailedPasswordAnswerAttemptWindowStart] DATETIME2         NOT NULL,
    [Comment]                                NTEXT            NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC),
    FOREIGN KEY ([ApplicationId]) REFERENCES [dbo].[aspnet_Applications] ([ApplicationId]),
);

次に、既存の情報を SQL メンバーシップ データベースから Identity 用に新しく追加されたテーブルにコピーする必要があります。 これは、あるテーブルから別のテーブルにデータを直接コピーすることで、SQL を使用して行うことができます。 テーブルの行にデータを追加するには、 コンストラクトを使用します INSERT INTO [Table] 。 別のテーブルからコピーするには、 INSERT INTO ステートメントと ステートメントを SELECT 使用できます。 すべてのユーザー情報を取得するには、 aspnet_Users テーブルと aspnet_Membership テーブルに対してクエリを実行し、そのデータを AspNetUsers テーブルにコピーする必要があります。 と SELECT と を INSERT INTO ステートメントLEFT OUTER JOINと共にJOIN使用します。 テーブル間でのデータのクエリとコピーの詳細については、 こちらの リンクを参照してください。 また、AspnetUserLogins テーブルと AspnetUserClaims テーブルは、既定でこれにマップされる情報が SQL メンバーシップにないため、最初は空です。 コピーされる情報は、ユーザーとロールのみです。 前の手順で作成したプロジェクトの場合、ユーザー テーブルに情報をコピーする SQL クエリは、次のようになります。

INSERT INTO AspNetUsers(Id,UserName,PasswordHash,SecurityStamp,EmailConfirmed,
PhoneNumber,PhoneNumberConfirmed,TwoFactorEnabled,LockoutEndDateUtc,LockoutEnabled,AccessFailedCount,
ApplicationId,LoweredUserName,MobileAlias,IsAnonymous,LastActivityDate,LegacyPasswordHash,
MobilePIN,Email,LoweredEmail,PasswordQuestion,PasswordAnswer,IsApproved,IsLockedOut,CreateDate,
LastLoginDate,LastPasswordChangedDate,LastLockoutDate,FailedPasswordAttemptCount,
FailedPasswordAnswerAttemptWindowStart,FailedPasswordAnswerAttemptCount,FailedPasswordAttemptWindowStart,Comment)
SELECT aspnet_Users.UserId,aspnet_Users.UserName,(aspnet_Membership.Password+'|'+CAST(aspnet_Membership.PasswordFormat as varchar)+'|'+aspnet_Membership.PasswordSalt),NewID(),
'true',NULL,'false','true',aspnet_Membership.LastLockoutDate,'true','0',
aspnet_Users.ApplicationId,aspnet_Users.LoweredUserName,
aspnet_Users.MobileAlias,aspnet_Users.IsAnonymous,aspnet_Users.LastActivityDate,aspnet_Membership.Password,
aspnet_Membership.MobilePIN,aspnet_Membership.Email,aspnet_Membership.LoweredEmail,aspnet_Membership.PasswordQuestion,aspnet_Membership.PasswordAnswer,
aspnet_Membership.IsApproved,aspnet_Membership.IsLockedOut,aspnet_Membership.CreateDate,aspnet_Membership.LastLoginDate,aspnet_Membership.LastPasswordChangedDate,
aspnet_Membership.LastLockoutDate,aspnet_Membership.FailedPasswordAttemptCount, aspnet_Membership.FailedPasswordAnswerAttemptWindowStart,
aspnet_Membership.FailedPasswordAnswerAttemptCount,aspnet_Membership.FailedPasswordAttemptWindowStart,aspnet_Membership.Comment
FROM aspnet_Users
LEFT OUTER JOIN aspnet_Membership ON aspnet_Membership.ApplicationId = aspnet_Users.ApplicationId 
AND aspnet_Users.UserId = aspnet_Membership.UserId;

上記の SQL ステートメントでは、 aspnet_Users テーブルと aspnet_Membership テーブルの各ユーザーに関する情報が AspnetUsers テーブルの列にコピーされます。 ここで行う唯一の変更は、パスワードをコピーする場合です。 SQL メンバーシップのパスワードの暗号化アルゴリズムでは 'PasswordSalt' と 'PasswordFormat' が使用されているため、ID によるパスワードの暗号化解除に使用できるように、ハッシュされたパスワードと共にコピーします。 これは、カスタム パスワードをフックする際の記事で詳しく説明されています。

このスクリプト ファイルは、このサンプルに固有のものです。 テーブルが追加されているアプリケーションの場合、開発者は同様の方法に従って、ユーザー モデル クラスにプロパティを追加し、AspnetUsers テーブルの列にマップできます。 スクリプトを実行するには、

  1. [サーバー エクスプローラー] を開きます。 [ApplicationServices] 接続を展開してテーブルを表示します。 [テーブル] ノードを右クリックし、[新しいクエリ] オプションを選択します

    Application Services 接続を展開してテーブルを表示する Open Server エクスプローラーのスクリーンショット。

  2. クエリ ウィンドウで、Migrations.sql ファイルから SQL スクリプト全体をコピーして貼り付けます。 [実行] 矢印ボタンを押してスクリプト ファイルを実行します。

    S Q L スクリプト全体をコピーして貼り付けるクエリ ウィンドウのスクリーンショット。

    [サーバー エクスプローラー] ウィンドウを更新します。 データベースに 5 つの新しいテーブルが作成されます。

    [サーバー エクスプローラー] ウィンドウを更新して、データベースに 5 つの新しいテーブルを作成するスクリーンショット。

    データ接続のテーブルのスクリーンショット。

    SQL メンバーシップ テーブルの情報を新しい ID システムにマップする方法を次に示します。

    aspnet_Roles --> AspNetRoles

    asp_netUsersとasp_netMembership --> AspNetUsers

    aspnet_UserInRoles --> AspNetUserRoles

    上記のセクションで説明したように、AspNetUserClaims テーブルと AspNetUserLogins テーブルは空です。 AspNetUser テーブルの '識別子' フィールドは、次の手順として定義されているモデル クラス名と一致する必要があります。 また、PasswordHash 列は 、'encrypted password |password salt|password format' の形式です。 これにより、特別な SQL メンバーシップ暗号化ロジックを使用して、古いパスワードを再利用できます。 これについては、この記事の後半で説明します。

モデルとメンバーシップ ページの作成

前述のように、ID 機能は Entity Framework を使用してデータベースと通信し、既定でアカウント情報を格納します。 テーブル内の既存のデータを操作するには、テーブルにマップして ID システムにフックするモデル クラスを作成する必要があります。 ID コントラクトの一部として、モデル クラスは Identity.Core dll で定義されているインターフェイスを実装するか、Microsoft.AspNet.Identity.EntityFramework で使用できるこれらのインターフェイスの既存の実装を拡張する必要があります。

このサンプルでは、AspNetRoles、AspNetUserClaims、AspNetLogins、および AspNetUserRole の各テーブルに、ID システムの既存の実装に似た列があります。 そのため、既存のクラスを再利用してこれらのテーブルにマップできます。 AspNetUser テーブルには、SQL メンバーシップ テーブルからの追加情報を格納するために使用される追加の列がいくつかあります。 これをマップするには、'IdentityUser' の既存の実装を拡張し、追加のプロパティを追加するモデル クラスを作成します。

  1. プロジェクトに Models フォルダーを作成し、User クラスを追加します。 クラスの名前は、'AspnetUsers' テーブルの '識別子' 列に追加されたデータと一致する必要があります。

    プロジェクトで Models フォルダーを作成し、User クラスを追加するスクリーンショット。

    User クラスは、 Microsoft.AspNet.Identity.EntityFramework dll にある IdentityUser クラスを 拡張する必要があります。 AspNetUser 列にマップするクラスのプロパティを宣言します。 プロパティ ID、Username、PasswordHash、SecurityStamp は IdentityUser で定義されているため、省略されます。 すべてのプロパティを持つ User クラスのコードを次に示します。

    public class User : IdentityUser
    {
        public User()
        {
            CreateDate = DateTime.Now;
            IsApproved = false;
            LastLoginDate = DateTime.Now;
            LastActivityDate = DateTime.Now;
            LastPasswordChangedDate = DateTime.Now;
            LastLockoutDate = DateTime.Parse("1/1/1754");
            FailedPasswordAnswerAttemptWindowStart = DateTime.Parse("1/1/1754");
            FailedPasswordAttemptWindowStart = DateTime.Parse("1/1/1754");
        }
    
        public System.Guid ApplicationId { get; set; }
        public string MobileAlias { get; set; }
        public bool IsAnonymous { get; set; }
        public System.DateTime LastActivityDate { get; set; }
        public string MobilePIN { get; set; }
        public string LoweredEmail { get; set; }
        public string LoweredUserName { get; set; }
        public string PasswordQuestion { get; set; }
        public string PasswordAnswer { get; set; }
        public bool IsApproved { get; set; }
        public bool IsLockedOut { get; set; }
        public System.DateTime CreateDate { get; set; }
        public System.DateTime LastLoginDate { get; set; }
        public System.DateTime LastPasswordChangedDate { get; set; }
        public System.DateTime LastLockoutDate { get; set; }
        public int FailedPasswordAttemptCount { get; set; }
        public System.DateTime FailedPasswordAttemptWindowStart { get; set; }
        public int FailedPasswordAnswerAttemptCount { get; set; }
        public System.DateTime FailedPasswordAnswerAttemptWindowStart { get; set; }
        public string Comment { get; set; }
    }
    
  2. Entity Framework DbContext クラスは、モデル内のデータをテーブルに保持し、テーブルからデータを取得してモデルを設定するために必要です。 Microsoft.AspNet.Identity.EntityFramework dll は、ID テーブルと対話して情報を取得および格納する IdentityDbContext クラスを定義します。 IdentityDbContext<tuser> は、IdentityUser クラスを拡張する任意のクラスである 'TUser' クラスを受け取ります。

    手順 1 で作成した 'User' クラスを渡して、'Models' フォルダーの下に IdentityDbContext を拡張する新しいクラス ApplicationDBContext を作成します

    public class ApplicationDbContext : IdentityDbContext<User>
    {
            
    }
    
  3. 新しい ID システムでのユーザー管理は、Microsoft.AspNet.Identity.EntityFramework dll で定義されている UserManager<tuser> クラスを使用して行われます。 手順 1 で作成した 'User' クラスを渡して、UserManager を拡張するカスタム クラスを作成する必要があります。

    Models フォルダーで、UserManager ユーザーを拡張する新しいクラス UserManager<を作成します>

    public class UserManager : UserManager<User>
    {
            
    }
    
  4. アプリケーションのユーザーのパスワードは暗号化され、データベースに格納されます。 SQL メンバーシップで使用される暗号化アルゴリズムは、新しい ID システムの暗号化アルゴリズムとは異なります。 古いパスワードを再利用するには、新しいユーザーの ID で暗号化アルゴリズムを使用しながら、古いユーザーが SQL メンバーシップ アルゴリズムを使用してログインするときに、パスワードを選択的に暗号化解除する必要があります。

    UserManager クラスには、'IPasswordHasher' インターフェイスを実装するクラスのインスタンスを格納するプロパティ 'PasswordHasher' があります。 これは、ユーザー認証トランザクション中にパスワードを暗号化/暗号化解除するために使用されます。 手順 3 で定義した UserManager クラスで、新しいクラス SQLPasswordHasher を作成し、次のコードをコピーします。

    public class SQLPasswordHasher : PasswordHasher
    {
        public override string HashPassword(string password)
        {
            return base.HashPassword(password);
        }
    
        public override PasswordVerificationResult VerifyHashedPassword(string  hashedPassword, string providedPassword)
        {
            string[] passwordProperties = hashedPassword.Split('|');
            if (passwordProperties.Length != 3)
            {
                return base.VerifyHashedPassword(hashedPassword, providedPassword);
            }
            else
            {
                string passwordHash = passwordProperties[0];
                int passwordformat = 1;
                string salt = passwordProperties[2];
                if (String.Equals(EncryptPassword(providedPassword, passwordformat, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
                {
                    return PasswordVerificationResult.SuccessRehashNeeded;
                }
                else
                {
                    return PasswordVerificationResult.Failed;
                }
            }
        }
    
        //This is copied from the existing SQL providers and is provided only for back-compat.
        private string EncryptPassword(string pass, int passwordFormat, string salt)
        {
            if (passwordFormat == 0) // MembershipPasswordFormat.Clear
                return pass;
    
            byte[] bIn = Encoding.Unicode.GetBytes(pass);
            byte[] bSalt = Convert.FromBase64String(salt);
            byte[] bRet = null;
    
            if (passwordFormat == 1)
            { // MembershipPasswordFormat.Hashed 
                HashAlgorithm hm = HashAlgorithm.Create("SHA1");
                if (hm is KeyedHashAlgorithm)
                {
                    KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
                    if (kha.Key.Length == bSalt.Length)
                    {
                        kha.Key = bSalt;
                    }
                    else if (kha.Key.Length < bSalt.Length)
                    {
                        byte[] bKey = new byte[kha.Key.Length];
                        Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
                        kha.Key = bKey;
                    }
                    else
                    {
                        byte[] bKey = new byte[kha.Key.Length];
                        for (int iter = 0; iter < bKey.Length; )
                        {
                            int len = Math.Min(bSalt.Length, bKey.Length - iter);
                            Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
                            iter += len;
                        }
                        kha.Key = bKey;
                    }
                    bRet = kha.ComputeHash(bIn);
                }
                else
                {
                    byte[] bAll = new byte[bSalt.Length + bIn.Length];
                    Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
                    Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
                    bRet = hm.ComputeHash(bAll);
                }
            }
    
            return Convert.ToBase64String(bRet);
        }
    

    System.Text 名前空間と System.Security.Cryptography 名前空間をインポートして、コンパイル エラーを解決します。

    EncodePassword メソッドは、既定の SQL メンバーシップ暗号化実装に従ってパスワードを暗号化します。 これは System.Web dll から取得されます。 古いアプリでカスタム実装が使用されている場合は、ここに反映する必要があります。 EncodePassword メソッドを使用して特定のパスワードをハッシュするか、データベースに存在するパスワードを使用してプレーン テキスト パスワードを検証する、HashPasswordVerifyHashedPassword という他の 2 つのメソッドを定義する必要があります。

    SQL メンバーシップ システムでは、PasswordHash、PasswordSalt、PasswordFormat を使用して、ユーザーがパスワードを登録または変更するときに入力したパスワードをハッシュしました。 移行中、3 つのフィールドはすべて、'|' 文字で区切られた AspNetUser テーブルの PasswordHash 列に格納されます。 ユーザーがログインし、パスワードにこれらのフィールドがある場合は、SQL メンバーシップ暗号化を使用してパスワードをチェックします。それ以外の場合は、ID システムの既定の暗号化を使用してパスワードを確認します。 このようにすると、古いユーザーは、アプリを移行した後にパスワードを変更する必要がなくなります。

  5. UserManager クラスのコンストラクターを宣言し、これを SQLPasswordHasher としてコンストラクターの プロパティに渡します。

    public UserManager()
                : base(new UserStore<User>(new ApplicationDbContext()))
    {
                this.PasswordHasher = new SQLPasswordHasher();
    }
    

新しいアカウント管理ページを作成する

移行の次の手順は、ユーザーが登録してログインできるようにするアカウント管理ページを追加することです。 SQL メンバーシップの古いアカウント ページでは、新しい ID システムでは機能しないコントロールが使用されます。 新しいユーザー管理ページを追加するには、プロジェクトを既に作成して NuGet パッケージを追加しているため、「アプリケーションにユーザーを登録するためのWeb Formsを追加する」の手順から、このリンクhttps://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-projectのチュートリアルに従います。

サンプルがここにあるプロジェクトで動作するように、いくつかの変更を加える必要があります。

  • Register.aspx.cs および Login.aspx.cs の分離コード クラスでは、ID パッケージの を UserManager 使用してユーザーを作成します。 この例では、前述の手順に従って、Models フォルダーに追加された UserManager を使用します。

  • Register.aspx.cs および Login.aspx.cs コードビハインド クラスで IdentityUser の代わりに作成された User クラスを使用します。 これにより、カスタム ユーザー クラスの ID システムにフックされます。

  • データベースを作成する部分はスキップできます。

  • 開発者は、現在のアプリケーション ID と一致するように、新しいユーザーの ApplicationId を設定する必要があります。 これを行うには、Register.aspx.cs クラスでユーザー オブジェクトが作成される前に、このアプリケーションの ApplicationId に対してクエリを実行し、ユーザーを作成する前に設定します。

    例:

    Register.aspx.cs ページでメソッドを定義して、aspnet_Applications テーブルに対してクエリを実行し、アプリケーション名に従ってアプリケーション ID を取得します

    private Guid GetApplicationID()
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
        {
            string queryString = "SELECT ApplicationId from aspnet_Applications WHERE ApplicationName = '/'"; //Set application name as in database
    
            SqlCommand command = new SqlCommand(queryString, connection);
            command.Connection.Open();
    
            var reader = command.ExecuteReader();
            while (reader.Read())
            {
                return reader.GetGuid(0);
            }
    
            return Guid.NewGuid();
        }
    }
    

    次に、ユーザー オブジェクトでこれを設定します

    var currentApplicationId = GetApplicationID();
    
    User user = new User() { UserName = Username.Text,
    ApplicationId=currentApplicationId, …};
    

既存のユーザーにログインするには、古いユーザー名とパスワードを使用します。 [登録] ページを使用して、新しいユーザーを作成します。 また、ユーザーが期待どおりにロール内にあることを確認します。

ID システムへの移植は、ユーザーが Open Authentication (OAuth) をアプリケーションに追加するのに役立ちます。 OAuth が有効になっているサンプル 参照してください。

次の手順

このチュートリアルでは、SQL メンバーシップから ASP.NET ID にユーザーを移植する方法を示しましたが、プロファイル データは移植しませんでした。 次のチュートリアルでは、SQL メンバーシップから新しい ID システムへのプロファイル データの移植について説明します。

フィードバックは、この記事の下部に残すことができます。

Tom Dykstra と Rick Anderson に記事を確認していただきありがとうございます。