Sdílet prostřednictvím


Migrace stávajícího webu z členství SQL na ASP.NET Identity

Rick Anderson, Suhas Joshi

Tento kurz ukazuje postup migrace existující webové aplikace s uživatelskými daty a daty rolí vytvořenými pomocí členství SQL do nového systému identit ASP.NET. Tento přístup zahrnuje změnu existujícího schématu databáze na schéma, které vyžaduje identita ASP.NET, a připojit k němu staré nebo nové třídy. Po přijetí tohoto přístupu se po migraci databáze budou budoucí aktualizace identity zpracovávat bez problémů.

V tomto kurzu použijeme šablonu webové aplikace (Web Forms) vytvořenou pomocí sady Visual Studio 2010 k vytvoření dat uživatelů a rolí. Pak použijeme skripty SQL k migraci stávající databáze do tabulek, které potřebuje systém identit. Dále nainstalujeme potřebné balíčky NuGet a přidáme nové stránky pro správu účtů, které pro správu členství používají systém identit. Jako test migrace by se uživatelé vytvořené pomocí členství SQL měli mít možnost přihlásit a noví uživatelé by se měli mít možnost zaregistrovat. Kompletní ukázku najdete tady. Viz také Migrace z členství ASP.NET na ASP.NET Identity.

Začínáme

Vytvoření aplikace s členstvím SQL

  1. Musíme začít s existující aplikací, která používá členství SQL a má data o uživatelích a rolích. Pro účely tohoto článku vytvoříme webovou aplikaci v sadě Visual Studio 2010.

    Snímek obrazovky s vytvořením webové aplikace v sadě Visual Studio 2010

  2. Pomocí nástroje ASP.NET Configuration vytvořte 2 uživatele: oldAdminUser a oldUser.

    Snímek obrazovky S P N E T Konfigurační nástroj pro vytvoření dvou uživatelů.

    Snímek obrazovky s nástrojem pro správu webu pro správu veškerého zabezpečení

  3. Vytvořte roli s názvem Správa a přidejte do této role uživatele oldAdminUser.

    Snímek obrazovky s Správa rolí vytvořenou jako uživatel v této roli

  4. Vytvořte Správa oddíl webu pomocí souboru Default.aspx. Nastavte autorizační značku v souboru web.config tak, aby povolte přístup jenom uživatelům ve Správa rolích. Další informace najdete tady. https://www.asp.net/web-forms/tutorials/security/roles/role-based-authorization-cs

    Snímek obrazovky s oddílem Správa webu

  5. Zobrazte databázi v Průzkumníku serveru a seznamte se s tabulkami vytvořenými systémem členství SQL. Přihlašovací data uživatele jsou uložená v tabulkách aspnet_Users a aspnet_Membership, zatímco data rolí jsou uložená v tabulce aspnet_Roles. Informace o tom, kteří uživatelé jsou ve kterých rolích jsou uloženy v tabulce aspnet_UsersInRoles. Pro základní správu členství stačí přenést informace z výše uvedených tabulek do systému ASP.NET Identity.

    Snímek obrazovky Průzkumníka serveru pro zobrazení databáze, abyste porozuměli tabulkám vytvořeným systémem členství V S Q L.

Migrace na Visual Studio 2013

  1. Nainstalujte Visual Studio Express 2013 pro web nebo Visual Studio 2013 spolu s nejnovějšími aktualizacemi.

  2. Otevřete výše uvedený projekt v nainstalované verzi sady Visual Studio. Pokud SQL Server Express není na počítači nainstalovaný, zobrazí se při otevření projektu výzva, protože připojovací řetězec používá SQL Express. Můžete buď nainstalovat SQL Express, nebo při řešení změnit připojovací řetězec na LocalDb. V tomto článku ho změníme na LocalDb.

  3. Otevřete web.config a změňte připojovací řetězec z . SQLExpress na (LocalDb)v11.0. Odeberte z připojovacího řetězce user instance=true.

    Snímek obrazovky se změnou připojovacího řetězce pro migraci na Visual Studio 2013

  4. Otevřete Průzkumníka serveru a ověřte, že je možné sledovat schéma a data tabulky.

  5. Systém identit ASP.NET funguje s architekturou verze 4.5 nebo vyšší. Změna cílení aplikace na verzi 4.5 nebo vyšší

    Snímek obrazovky S P N E T Identifikační systém.

    Sestavte projekt a ověřte, že nedošlo k žádným chybám.

Instalace balíčků NuGet

  1. V Průzkumník řešení klikněte pravým tlačítkem na projekt >Spravovat balíčky NuGet. Do vyhledávacího pole zadejte "Asp.net Identita". V seznamu výsledků vyberte balíček a klikněte na nainstalovat. Přijměte licenční smlouvu kliknutím na tlačítko Přijmout. Všimněte si, že tento balíček nainstaluje balíčky závislostí: EntityFramework a Microsoft ASP.NET Identity Core. Podobně nainstalujte následující balíčky (pokud nechcete povolit přihlášení OAuth, přeskočte poslední 4 balíčky 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

      Snímek obrazovky s instalací balíčků NuGet v Průzkumník řešení

Migrace databáze do nového systému identit

Dalším krokem je migrace existující databáze do schématu požadovaného systémem ASP.NET Identity. Abychom toho dosáhli, spustíme skript SQL, který obsahuje sadu příkazů pro vytváření nových tabulek a migraci existujících uživatelských informací do nových tabulek. Soubor skriptu najdete tady.

Tento soubor skriptu je specifický pro tuto ukázku. Pokud je schéma pro tabulky vytvořené pomocí členství SQL přizpůsobeno nebo změněno, je potřeba odpovídajícím způsobem změnit skripty.

Jak vygenerovat skript SQL pro migraci schématu

Aby třídy identity ASP.NET fungovaly s daty stávajících uživatelů, musíme migrovat schéma databáze do schématu, které potřebuje ASP.NET Identity. Můžeme to udělat přidáním nových tabulek a zkopírováním existujících informací do těchto tabulek. Ve výchozím nastavení ASP.NET Identity používá EntityFramework k mapování tříd modelu identit zpět do databáze pro ukládání nebo načítání informací. Tyto třídy modelu implementují základní rozhraní identity definující objekty uživatelů a rolí. Tabulky a sloupce v databázi jsou založené na těchto třídách modelu. Třídy modelu EntityFramework ve službě Identity v2.1.0 a jejich vlastnosti jsou definované níže.

IdentityUser Typ Role identity IdentitaUserRole IdentityUserLogin IdentityUserClaim
Id řetězec Id Id role ProviderKey Id
Uživatelské jméno řetězec Název UserId UserId Typ deklarace identity
PasswordHash (Hodnota hash hesla) řetězec LoginProvider Deklarace identity
SecurityStamp řetězec User_id
E-mail řetězec
Potvrzení e-mailu bool
PhoneNumber řetězec
PhoneNumberConfirmed bool
LockoutEnabled bool
LockoutEndDate DateTime
AccessFailedCount int

Pro každý z těchto modelů musíme mít tabulky se sloupci odpovídajícími vlastnostem. Mapování mezi třídami a tabulkami je definováno OnModelCreating v metodě objektu IdentityDBContext. To se označuje jako metoda konfigurace fluent API a další informace najdete tady. Konfigurace pro třídy je, jak je uvedeno níže.

Třída Tabulka Primární klíč Cizí klíč
IdentityUser AspnetUsers Id
Role identity Role aspnet Id
IdentitaRole uživatele Role uživatele aspnetu UserId + RoleId User_Id-AspnetUsers> RoleId-AspnetRoles>
IdentityUserLogin AspnetUserLogins ProviderKey+UserId+ LoginProvider UserId-AspnetUsers>
IdentityUserClaim AspnetUserClaims Id User_Id-AspnetUsers>

Pomocí těchto informací můžeme vytvořit příkazy SQL pro vytvoření nových tabulek. Každý příkaz můžeme napsat zvlášť nebo vygenerovat celý skript pomocí příkazů PowerShellu EntityFramework, které pak můžeme podle potřeby upravit. Uděláte to tak, že v sadě Visual Studio otevřete konzolu Správce balíčků z nabídky Zobrazení nebo Nástroje .

  • Spuštěním příkazu Enable-Migrations povolte migrace EntityFramework.
  • Spusťte příkaz Add-migration initial, který vytvoří počáteční instalační kód pro vytvoření databáze v C#/VB.
  • Posledním krokem je spuštění příkazu Update-Database –Script, který vygeneruje skript SQL na základě tříd modelu.

Některé příkazy nejsou podporované, pokud aplikace jako úložiště dat identity používá SQLite. Kvůli omezením databázového stroje Alter vyvolají příkazy následující výjimku:

System.NotSupportedException: SQLite nepodporuje tuto operaci migrace.

Obejdete to tak, že v databázi spustíte migrace Code First a změníte tabulky.

Tento skript pro generování databáze je možné použít jako začátek, kdy provedeme další změny pro přidání nových sloupců a kopírování dat. Výhodou je, že vygenerujeme _MigrationHistory tabulku, kterou EntityFramework používá k úpravě schématu databáze při změně tříd modelu pro budoucí verze verzí identity.

Informace o uživatelích členství SQL měly kromě vlastností ve třídě modelu uživatele Identity i další vlastnosti: e-mail, pokusy o heslo, datum posledního přihlášení, datum posledního uzamčení atd. Jedná se o užitečné informace a chtěli bychom, aby se přenášely do systému identit. Můžete to provést přidáním dalších vlastností do modelu uživatele a jejich namapováním zpět na sloupce tabulky v databázi. Můžeme to udělat přidáním třídy, která model podtřídy IdentityUser . Do této vlastní třídy můžeme přidat vlastnosti a úpravou skriptu SQL přidat odpovídající sloupce při vytváření tabulky. Kód pro tuto třídu je popsán dále v článku. Skript SQL pro vytvoření AspnetUsers tabulky po přidání nových vlastností by byl

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]),
);

Dále musíme zkopírovat existující informace z databáze členství SQL do nově přidaných tabulek identity. Můžete to provést prostřednictvím SQL zkopírováním dat přímo z jedné tabulky do druhé. K přidání dat do řádků tabulky použijeme INSERT INTO [Table] konstruktor . Ke kopírování z jiné tabulky můžeme použít INSERT INTO příkaz spolu s příkazem SELECT . Abychom získali všechny informace o uživateli, musíme se dotazovat na aspnet_Users a aspnet_Membership tabulky a zkopírovat data do tabulky AspNetUsers . Používáme příkazy INSERT INTO a SELECT spolu s JOIN a .LEFT OUTER JOIN Další informace o dotazování a kopírování dat mezi tabulkami najdete na tomto odkazu. Tabulky AspnetUserLogins a AspnetUserClaims jsou pro začátek prázdné, protože v členství SQL nejsou žádné informace, které by se na tuto hodnotu ve výchozím nastavení mapují. Jediné zkopírované informace jsou pro uživatele a role. V případě projektu vytvořeného v předchozích krocích by byl dotaz SQL na zkopírování informací do tabulky users (Uživatelé).

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;

Ve výše uvedeném příkazu SQL se informace o každém uživateli z aspnet_Users a aspnet_Membership tabulek zkopírují do sloupců tabulky AspnetUsers . Jediná změna, která se tady provede, je zkopírování hesla. Vzhledem k tomu, že šifrovací algoritmus pro hesla v rámci členství SQL používal PasswordSalt a PasswordFormat, zkopírujeme také tento algoritmus spolu s hashovaným heslem, aby se mohl použít k dešifrování hesla pomocí identity. To je vysvětleno dále v článku při připojení vlastního hesla hasher.

Tento soubor skriptu je specifický pro tuto ukázku. U aplikací, které mají další tabulky, mohou vývojáři použít podobný přístup k přidání dalších vlastností do třídy modelu uživatele a jejich mapování na sloupce v tabulce AspnetUsers. Skript spustíte tak, že

  1. Otevřete Průzkumníka serveru. Rozbalte připojení ApplicationServices a zobrazte tabulky. Klikněte pravým tlačítkem na uzel Tabulky a vyberte možnost Nový dotaz.

    Snímek obrazovky s otevřením Průzkumníka serveru pro rozbalení připojení aplikačních služeb a zobrazením tabulek

  2. V okně dotazu zkopírujte a vložte celý skript SQL ze souboru Migrations.sql. Spusťte soubor skriptu stisknutím tlačítka se šipkou Spustit.

    Snímek obrazovky s oknem dotazu pro zkopírování a vložení celého skriptu S Q L

    Aktualizujte okno Průzkumník serveru. V databázi se vytvoří pět nových tabulek.

    Snímek obrazovky s aktualizací okna Průzkumníka serveru a vytvořením pěti nových tabulek v databázi

    Snímek obrazovky s tabulkami v datových připojeních

    Níže je uvedeno, jak se informace v tabulkách členství SQL mapují na nový systém identit.

    aspnet_Roles –> AspNetRoles

    asp_netUsers a asp_netMembership –> AspNetUsers

    aspnet_UserInRoles –> AspNetUserRoles

    Jak je vysvětleno v předchozí části, tabulky AspNetUserClaims a AspNetUserLogins jsou prázdné. Pole "Discriminator" v tabulce AspNetUser by se mělo shodovat s názvem třídy modelu, který je definován jako další krok. Sloupec PasswordHash je také ve formátu "šifrované heslo |heslo salt|formát hesla". To vám umožní použít speciální kryptografickou logiku členství SQL, abyste mohli znovu použít stará hesla. To je vysvětleno v pozdější části článku.

Vytváření modelů a stránek členství

Jak už bylo zmíněno dříve, funkce Identita ve výchozím nastavení používá Entity Framework ke komunikaci s databází za účelem ukládání informací o účtu. Abychom mohli pracovat s existujícími daty v tabulce, potřebujeme vytvořit třídy modelu, které se mapují zpět na tabulky a připojují je do systému identit. Jako součást kontraktu Identity by třídy modelu měly buď implementovat rozhraní definovaná v knihovně DLL Identity.Core, nebo mohou rozšířit stávající implementaci těchto rozhraní dostupných v Microsoft.AspNet.Identity.EntityFramework.

Tabulky AspNetRoles, AspNetUserClaims, AspNetLogins a AspNetUserRole v naší ukázce obsahují sloupce, které se podobají stávající implementaci systému identit. Proto můžeme znovu použít existující třídy pro mapování na tyto tabulky. Tabulka AspNetUser obsahuje několik dalších sloupců, které slouží k ukládání dalších informací z tabulek členství SQL. To lze mapovat vytvořením třídy modelu, která rozšiřuje existující implementaci 'IdentityUser' a přidat další vlastnosti.

  1. Vytvořte v projektu složku Models a přidejte třídu User. Název třídy by se měl shodovat s daty přidanou ve sloupci Diskriminátor v tabulce AspnetUsers.

    Snímek obrazovky s vytvořením složky Models v projektu a přidáním třídy User

    Třída User by měla rozšířit třídu IdentityUser v knihovně DLL Microsoft.AspNet.Identity.EntityFramework . Deklarujte vlastnosti ve třídě, které mapují zpět na sloupce AspNetUser. Vlastnosti ID, Username, PasswordHash a SecurityStamp jsou definovány v objektu IdentityUser, a proto jsou vynechány. Níže je kód pro třídu User, která má všechny vlastnosti.

    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. Třída DbContext pro Entity Framework se vyžaduje k uchování dat v modelech zpět do tabulek a načtení dat z tabulek za účelem naplnění modelů. Knihovna DLL Microsoft.AspNet.Identity.EntityFramework definuje třídu IdentityDbContext, která pracuje s tabulkami Identity za účelem načtení a ukládání informací. Tuser> IdentityDbContext<přebírá třídu TUser, která může být libovolnou třídou, která rozšiřuje třídu IdentityUser.

    Vytvořte novou třídu ApplicationDBContext, která rozšiřuje IdentityDbContext ve složce Models a předá třídu User vytvořenou v kroku 1.

    public class ApplicationDbContext : IdentityDbContext<User>
    {
            
    }
    
  3. Správa uživatelů v novém systému identit se provádí pomocí třídy tuser> UserManager<definované v knihovně DLL Microsoft.AspNet.Identity.EntityFramework. Potřebujeme vytvořit vlastní třídu, která rozšíří userManager a předá třídu User vytvořenou v kroku 1.

    Ve složce Modely vytvořte novou třídu UserManager, která rozšiřuje uživatele UserManager<.>

    public class UserManager : UserManager<User>
    {
            
    }
    
  4. Hesla uživatelů aplikace jsou zašifrovaná a uložená v databázi. Kryptografický algoritmus používaný při členství v SQL se liší od algoritmu v novém systému identit. Abychom mohli znovu použít stará hesla, musíme selektivně dešifrovat hesla, když se staří uživatelé přihlašují pomocí algoritmu členství SQL, zatímco pro nové uživatele použijeme kryptografický algoritmus v identitě.

    Třída UserManager má vlastnost PasswordHasher, která ukládá instanci třídy, která implementuje rozhraní IPasswordHasher. Používá se k šifrování/dešifrování hesel během transakcí ověřování uživatelů. Ve třídě UserManager definované v kroku 3 vytvořte novou třídu SQLPasswordHasher a zkopírujte níže uvedený kód.

    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);
        }
    

    Chyby kompilace vyřešíte importem oborů názvů System.Text a System.Security.Cryptography.

    EncodePassword Metoda šifruje heslo podle výchozího členství SQL kryptografické implementace. Tento soubor je převzat z knihovny DLL System.Web. Pokud stará aplikace používala vlastní implementaci, měla by se to tady projevit. Potřebujeme definovat dvě další metody HashPassword a VerifyHashedPassword , které používají Metodu EncodePassword k hashování daného hesla nebo ověření hesla ve formátu prostého textu s heslem existujícím v databázi.

    Systém členství SQL použil PasswordHash, PasswordSalt a PasswordFormat k hashování hesla zadaného uživateli při registraci nebo změně hesla. Během migrace jsou všechna tři pole uložena ve sloupci PasswordHash v tabulce AspNetUser oddělená znakem |. Když se uživatel přihlásí a heslo obsahuje tato pole, použijeme ke kontrole hesla kryptografické členství SQL. v opačném případě použijeme k ověření hesla výchozí šifrování systému identit. Díky tomu by si staří uživatelé nemuseli po migraci aplikace měnit hesla.

  5. Deklarujte konstruktor třídy UserManager a předejte ji jako SQLPasswordHasher do vlastnosti v konstruktoru.

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

Vytvořit nové stránky pro správu účtů

Dalším krokem při migraci je přidání stránek pro správu účtů, které umožní registraci a přihlášení uživatele. Staré stránky účtů z členství SQL používají ovládací prvky, které s novým systémem identit nefungují. Pokud chcete přidat nové stránky pro správu uživatelů, postupujte podle kurzu na tomto odkazu https://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-project počínaje krokem "Přidání Web Forms pro registraci uživatelů do vaší aplikace", protože jsme už vytvořili projekt a přidali balíčky NuGet.

Abychom mohli v ukázce pracovat s projektem, který tady máme, musíme udělat nějaké změny.

  • Kód Register.aspx.cs a Login.aspx.cs na pozadí třídy používá UserManager z balíčků identity k vytvoření uživatele. V tomto příkladu použijte UserManager přidaný do složky Modely podle výše uvedených kroků.

  • Použijte třídu User vytvořenou místo IdentityUser v kódu Register.aspx.cs a Login.aspx.cs za třídami. Tím se naše vlastní třída uživatelů připojí k systému identit.

  • Část pro vytvoření databáze se dá přeskočit.

  • Vývojář musí nastavit ApplicationId pro nového uživatele tak, aby odpovídala aktuálnímu ID aplikace. To lze provést dotazováním ApplicationId pro tuto aplikaci před vytvořením objektu uživatele ve třídě Register.aspx.cs a jeho nastavením před vytvořením uživatele.

    Příklad:

    Na stránce Register.aspx.cs definujte metodu pro dotazování aspnet_Applications tabulky a získání ID aplikace podle názvu aplikace.

    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();
        }
    }
    

    Teď ho nastavte u objektu uživatele.

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

K přihlášení existujícího uživatele použijte staré uživatelské jméno a heslo. Pomocí stránky Zaregistrovat vytvořte nového uživatele. Ověřte také, že jsou uživatelé v rolích podle očekávání.

Přenos do systému identit pomáhá uživateli přidat do aplikace otevřené ověřování (OAuth). Projděte si ukázku , která má povolený protokol OAuth.

Další kroky

V tomto kurzu jsme ukázali, jak přenést uživatele z členství SQL na ASP.NET Identity, ale nepřepojili jsme data profilu. V dalším kurzu se podíváme na přenos dat profilu z členství SQL do nového systému identit.

Svůj názor můžete zanechat na konci tohoto článku.

Díky Tom Dykstra a Rick Anderson za přezkoumání článku.