Migrowanie istniejącej witryny internetowej z członkostwa SQL do systemu ASP.NET Identity
Autor : Rick Anderson, Suhas Joshi
W tym samouczku przedstawiono kroki migracji istniejącej aplikacji internetowej z danymi użytkownika i roli utworzonymi przy użyciu członkostwa SQL w nowym systemie tożsamości ASP.NET. Takie podejście polega na zmianie istniejącego schematu bazy danych na wymagany przez ASP.NET Identity i przypinanie do niego starych/nowych klas. Po przyjęciu tego podejścia po przeprowadzeniu migracji bazy danych przyszłe aktualizacje tożsamości będą obsługiwane bez wysiłku.
Na potrzeby tego samouczka utworzymy szablon aplikacji internetowej (Web Forms) utworzony przy użyciu programu Visual Studio 2010 w celu utworzenia danych użytkownika i roli. Następnie użyjemy skryptów SQL, aby zmigrować istniejącą bazę danych do tabel wymaganych przez system tożsamości. Następnie zainstalujemy niezbędne pakiety NuGet i dodamy nowe strony zarządzania kontami, które używają systemu tożsamości do zarządzania członkostwem. Podczas testowania migracji użytkownicy utworzeni przy użyciu członkostwa SQL powinni mieć możliwość logowania, a nowi użytkownicy powinni mieć możliwość rejestrowania. Pełny przykład można znaleźć tutaj. Zobacz również Migrowanie z członkostwa ASP.NET do tożsamości ASP.NET.
Wprowadzenie
Tworzenie aplikacji z członkostwem SQL
Musimy zacząć od istniejącej aplikacji, która używa członkostwa SQL i ma dane użytkownika i roli. Na potrzeby tego artykułu utworzymy aplikację internetową w programie Visual Studio 2010.
Za pomocą narzędzia ASP.NET Configuration utwórz 2 użytkowników: oldAdminUser i oldUser.
Utwórz rolę o nazwie Administracja i dodaj rolę "oldAdminUser" jako użytkownik w tej roli.
Utwórz sekcję Administracja witryny przy użyciu pliku Default.aspx. Ustaw tag autoryzacji w pliku web.config, aby umożliwić dostęp tylko do użytkowników w rolach Administracja. Więcej informacji można znaleźć tutaj https://www.asp.net/web-forms/tutorials/security/roles/role-based-authorization-cs
Wyświetl bazę danych w Eksploratorze serwera, aby poznać tabele utworzone przez system członkostwa SQL. Dane logowania użytkownika są przechowywane w tabelach aspnet_Users i aspnet_Membership, podczas gdy dane roli są przechowywane w tabeli aspnet_Roles. Informacje o tym, którzy użytkownicy są przechowywani w tabeli aspnet_UsersInRoles. W przypadku podstawowego zarządzania członkostwem wystarczy przekierować informacje z powyższych tabel do systemu ASP.NET Identity.
Migrowanie do Visual Studio 2013
Zainstaluj Visual Studio Express 2013 dla sieci Web lub Visual Studio 2013 wraz z najnowszymi aktualizacjami.
Otwórz powyższy projekt w zainstalowanej wersji programu Visual Studio. Jeśli SQL Server Express nie jest zainstalowana na maszynie, po otwarciu projektu zostanie wyświetlony monit, ponieważ parametry połączenia używają programu SQL Express. Możesz wybrać instalację programu SQL Express lub w miarę obejścia zmiany parametrów połączenia na LocalDb. W tym artykule zmienimy go na LocalDb.
Otwórz web.config i zmień parametry połączenia z . SQLExpress do (LocalDb)v11.0. Usuń element "User Instance=true" z parametrów połączenia.
Otwórz Eksploratora serwera i sprawdź, czy można zaobserwować schemat i dane tabeli.
System ASP.NET Identity współdziała z wersją 4.5 lub nowszą platformy. Przekieruj aplikację do wersji 4.5 lub nowszej.
Skompiluj projekt, aby sprawdzić, czy nie ma żadnych błędów.
Instalowanie pakietów Nuget
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt Zarządzaj pakietami> NuGet. W polu wyszukiwania wprowadź "Asp.net Tożsamość". Wybierz pakiet na liście wyników, a następnie kliknij przycisk Zainstaluj. Zaakceptuj umowę licencyjną, klikając przycisk "Akceptuję". Należy pamiętać, że ten pakiet zainstaluje pakiety zależności: EntityFramework i Microsoft ASP.NET Identity Core. Podobnie zainstaluj następujące pakiety (pomiń ostatnie 4 pakiety OWIN, jeśli nie chcesz włączyć logowania OAuth):
Microsoft.AspNet.Identity.Owin
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security.Facebook
Microsoft.Owin.Security.Google
Microsoft.Owin.Security.MicrosoftAccount
Microsoft.Owin.Security.Twitter
Migrowanie bazy danych do nowego systemu tożsamości
Następnym krokiem jest migracja istniejącej bazy danych do schematu wymaganego przez system ASP.NET Identity. Aby to osiągnąć, uruchomimy skrypt SQL zawierający zestaw poleceń w celu utworzenia nowych tabel i zmigrowania istniejących informacji o użytkowniku do nowych tabel. Plik skryptu można znaleźć tutaj.
Ten plik skryptu jest specyficzny dla tego przykładu. Jeśli schemat tabel utworzonych przy użyciu członkostwa SQL został dostosowany lub zmodyfikowany, należy odpowiednio zmienić skrypty.
Jak wygenerować skrypt SQL na potrzeby migracji schematu
Aby klasy ASP.NET Identity działały bez użycia danych istniejących użytkowników, musimy przeprowadzić migrację schematu bazy danych do klasy wymaganej przez usługę ASP.NET Identity. Możemy to zrobić, dodając nowe tabele i kopiując istniejące informacje do tych tabel. Domyślnie ASP.NET Identity używa elementu EntityFramework do mapowania klas modelu tożsamości z powrotem do bazy danych w celu przechowywania/pobierania informacji. Te klasy modeli implementują podstawowe interfejsy tożsamości definiujące obiekty użytkownika i roli. Tabele i kolumny w bazie danych są oparte na tych klasach modelu. Klasy modelu EntityFramework w usłudze Identity w wersji 2.1.0 i ich właściwości są zdefiniowane poniżej
IdentityUser | Typ | IdentityRole | IdentityUserRole | IdentityUserLogin | IdentityUserClaim |
---|---|---|---|---|---|
Id | ciąg | Id | Identyfikator roli | Klucz dostawcy | Id |
Nazwa użytkownika | ciąg | Nazwa | UserId | UserId | Claimtype |
PasswordHash | ciąg | LoginProvider | ClaimValue | ||
SecurityStamp | ciąg | User_id | |||
ciąg | |||||
EmailConfirmed | bool | ||||
PhoneNumber | ciąg | ||||
PhoneNumberConfirmed | bool | ||||
LockoutEnabled | bool | ||||
LockoutEndDate | DateTime | ||||
AccessFailedCount | int |
Musimy mieć tabele dla każdego z tych modeli z kolumnami odpowiadającymi właściwościom. Mapowanie między klasami i tabelami jest definiowane w OnModelCreating
metodzie IdentityDBContext
. Jest to znane jako płynna metoda konfiguracji interfejsu API i więcej informacji można znaleźć tutaj. Konfiguracja klas jest jak wspomniano poniżej
Klasa | Tabela | Klucz podstawowy | Klucz obcy |
---|---|---|---|
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> |
Dzięki tym informacjom możemy utworzyć instrukcje SQL w celu utworzenia nowych tabel. Możemy napisać każdą instrukcję indywidualnie lub wygenerować cały skrypt przy użyciu poleceń programu PowerShell EntityFramework, które następnie możemy edytować zgodnie z potrzebami. W tym celu w programie VS otwórz konsolę Menedżera pakietów z menu Widok lub Narzędzia
- Uruchom polecenie "Enable-Migrations", aby włączyć migracje entityFramework.
- Uruchom polecenie "Add-migration initial", które tworzy początkowy kod konfiguracji w celu utworzenia bazy danych w języku C#/VB.
- Ostatnim krokiem jest uruchomienie polecenia "Update-Database –Script", które generuje skrypt SQL na podstawie klas modelu.
Niektóre polecenia nie są obsługiwane, jeśli aplikacja używa biblioteki SQLite jako magazynu danych identity. Ze względu na ograniczenia aparatu bazy danych
Alter
polecenia zgłaszają następujący wyjątek:"System.NotSupportedException: SQLite nie obsługuje tej operacji migracji".
W miarę pracy uruchom migracje Code First w bazie danych, aby zmienić tabele.
Ten skrypt generowania bazy danych może służyć jako początek, w którym wprowadzimy dodatkowe zmiany w celu dodania nowych kolumn i skopiowania danych. Zaletą tej funkcji jest wygenerowanie _MigrationHistory
tabeli, która jest używana przez element EntityFramework do modyfikowania schematu bazy danych, gdy klasy modeli zmieniają się w przyszłych wersjach wersji usługi Identity.
Informacje o użytkowniku członkostwa SQL miały inne właściwości oprócz tych w klasie Modelu użytkownika Tożsamości, czyli e-mail, próbach hasła, dacie ostatniego logowania, ostatniej dacie blokady itp. Jest to przydatne informacje i chcemy, aby były przenoszone do systemu tożsamości. Można to zrobić, dodając dodatkowe właściwości do modelu użytkownika i mapując je z powrotem do kolumn tabeli w bazie danych. Możemy to zrobić, dodając klasę, która podklasuje IdentityUser
model. Możemy dodać właściwości do tej klasy niestandardowej i edytować skrypt SQL, aby dodać odpowiednie kolumny podczas tworzenia tabeli. Kod dla tej klasy został opisany w dalszej części artykułu. Skrypt SQL do tworzenia AspnetUsers
tabeli po dodaniu nowych właściwości będzie
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]),
);
Następnie musimy skopiować istniejące informacje z bazy danych członkostwa SQL do nowo dodanych tabel dla usługi Identity. Można to zrobić za pomocą języka SQL, kopiując dane bezpośrednio z jednej tabeli do innej. Aby dodać dane do wierszy tabeli, użyjemy INSERT INTO [Table]
konstrukcji. Aby skopiować z innej tabeli, możemy użyć INSERT INTO
instrukcji wraz z instrukcją SELECT
. Aby uzyskać wszystkie informacje o użytkowniku, musimy wykonać zapytanie dotyczące tabel aspnet_Users i aspnet_Membership oraz skopiować dane do tabeli AspNetUsers . Używamy instrukcji INSERT INTO
JOIN
i SELECT
i.LEFT OUTER JOIN
Aby uzyskać więcej informacji na temat wykonywania zapytań i kopiowania danych między tabelami, zapoznaj się z tym linkiem. Ponadto tabele AspnetUserLogins i AspnetUserClaims są puste, ponieważ domyślnie nie ma żadnych informacji w członkostwie SQL, które są mapowane na tę wartość. Jedyne skopiowane informacje są przeznaczone dla użytkowników i ról. W przypadku projektu utworzonego w poprzednich krokach zapytanie SQL w celu skopiowania informacji do tabeli users będzie
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;
W powyższej instrukcji SQL informacje o każdym użytkowniku z tabel aspnet_Users i aspnet_Membership są kopiowane do kolumn tabeli AspnetUsers . Jedyną modyfikacją wykonaną w tym miejscu jest skopiowanie hasła. Ponieważ algorytm szyfrowania haseł w członkostwie SQL używał wartości "PasswordSalt" i "PasswordFormat", skopiujemy to również wraz z hasłem skrótu, aby można było go użyć do odszyfrowania hasła według tożsamości. Wyjaśniono to w dalszej części artykułu podczas podłączania hasła niestandardowego.
Ten plik skryptu jest specyficzny dla tego przykładu. W przypadku aplikacji, które mają dodatkowe tabele, deweloperzy mogą stosować podobne podejście do dodawania dodatkowych właściwości w klasie modelu użytkownika i mapować je na kolumny w tabeli AspnetUsers. Aby uruchomić skrypt,
Otwórz Eksploratora serwera. Rozwiń połączenie "ApplicationServices", aby wyświetlić tabele. Kliknij prawym przyciskiem myszy węzeł Tabele i wybierz opcję "Nowe zapytanie"
W oknie zapytania skopiuj i wklej cały skrypt SQL z pliku Migrations.sql. Uruchom plik skryptu, naciskając przycisk strzałki "Wykonaj".
Odśwież okno Eksplorator serwera. W bazie danych są tworzone pięć nowych tabel.
Poniżej przedstawiono sposób mapowania informacji w tabelach członkostwa SQL do nowego systemu tożsamości.
aspnet_Roles —> AspNetRoles
asp_netUsers i asp_netMembership —> AspNetUsers
aspnet_UserInRoles —> AspNetUserRoles
Jak wyjaśniono w powyższej sekcji, tabele AspNetUserClaims i AspNetUserLogins są puste. Pole "Dyskryminujące" w tabeli AspNetUser powinno być zgodne z nazwą klasy modelu, która jest zdefiniowana jako następny krok. Ponadto kolumna PasswordHash znajduje się w postaci "zaszyfrowane hasło |password salt|password format". Dzięki temu można używać specjalnej logiki kryptograficznej członkostwa SQL, aby można było ponownie używać starych haseł. Wyjaśniono to w dalszej części artykułu.
Tworzenie modeli i stron członkostwa
Jak wspomniano wcześniej, funkcja Identity używa programu Entity Framework do komunikacji z bazą danych do przechowywania informacji o koncie domyślnie. Aby pracować z istniejącymi danymi w tabeli, musimy utworzyć klasy modelu, które są mapowania z powrotem do tabel i podłączać je do systemu Tożsamości. W ramach kontraktu tożsamości klasy modelu powinny implementować interfejsy zdefiniowane w bibliotece DLL Identity.Core lub rozszerzyć istniejącą implementację tych interfejsów dostępnych w elemecie Microsoft.AspNet.Identity.EntityFramework.
W naszym przykładzie tabele AspNetRoles, AspNetUserClaims, AspNetLogins i AspNetUserRole zawierają kolumny podobne do istniejącej implementacji systemu Identity. W związku z tym możemy ponownie użyć istniejących klas do mapowania na te tabele. Tabela AspNetUser zawiera dodatkowe kolumny, które są używane do przechowywania dodatkowych informacji z tabel członkostwa SQL. Można to zamapować, tworząc klasę modelu, która rozszerza istniejącą implementację klasy "IdentityUser" i dodaje dodatkowe właściwości.
Utwórz folder Models w projekcie i dodaj klasę User. Nazwa klasy powinna być zgodna z danymi dodanymi w kolumnie "Dyskryminator" tabeli "AspnetUsers".
Klasa User powinna rozszerzyć klasę IdentityUser znajdującą się w bibliotece dll Microsoft.AspNet.Identity.EntityFramework . Zadeklaruj właściwości w klasie mapujące z powrotem na kolumny AspNetUser. Właściwości ID, Username, PasswordHash i SecurityStamp są zdefiniowane w identityUser i dlatego są pomijane. Poniżej znajduje się kod klasy User, który ma wszystkie właściwości
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; } }
Klasa DbContext programu Entity Framework jest wymagana do utrwalania danych w modelach z powrotem do tabel i pobierania danych z tabel w celu wypełnienia modeli. Biblioteka DLL Microsoft.AspNet.Identity.EntityFramework definiuje klasę IdentityDbContext, która współdziała z tabelami Identity w celu pobierania i przechowywania informacji. Element tuser> IdentityDbContext<przyjmuje klasę "TUser", która może być dowolną klasą rozszerzającą klasę IdentityUser.
Utwórz nową klasę ApplicationDBContext, która rozszerza element IdentityDbContext w folderze "Models", przekazując klasę "User" utworzoną w kroku 1
public class ApplicationDbContext : IdentityDbContext<User> { }
Zarządzanie użytkownikami w nowym systemie tożsamości odbywa się przy użyciu klasy tuser> UserManager<zdefiniowanej w bibliotece dll Microsoft.AspNet.Identity.EntityFramework. Musimy utworzyć klasę niestandardową, która rozszerza klasę UserManager, przekazując klasę "Użytkownik" utworzoną w kroku 1.
W folderze Models utwórz nową klasę UserManager, która rozszerza użytkownika UserManager<>
public class UserManager : UserManager<User> { }
Hasła użytkowników aplikacji są szyfrowane i przechowywane w bazie danych. Algorytm kryptograficzny używany w członkostwie SQL różni się od algorytmu w nowym systemie tożsamości. Aby ponownie używać starych haseł, należy selektywnie odszyfrować hasła, gdy starzy użytkownicy logują się przy użyciu algorytmu członkostwa SQL podczas korzystania z algorytmu kryptograficznego w tożsamości dla nowych użytkowników.
Klasa UserManager ma właściwość "PasswordHasher", która przechowuje wystąpienie klasy implementujące interfejs "IPasswordHasher". Służy to do szyfrowania/odszyfrowywania haseł podczas transakcji uwierzytelniania użytkownika. W klasie UserManager zdefiniowanej w kroku 3 utwórz nową klasę SQLPasswordHasher i skopiuj poniższy kod.
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); }
Rozwiąż błędy kompilacji, importując przestrzenie nazw System.Text i System.Security.Cryptography.
Metoda EncodePassword szyfruje hasło zgodnie z domyślną implementacją kryptograficzną członkostwa SQL. Jest to pobierane z biblioteki Dll System.Web. Jeśli stara aplikacja użyła implementacji niestandardowej, powinna ona zostać odzwierciedlona w tym miejscu. Musimy zdefiniować dwie inne metody HashPassword i VerifyHashedPassword , które używają metody EncodePassword w celu utworzenia skrótu danego hasła lub zweryfikowania hasła w postaci zwykłego tekstu przy użyciu hasła istniejącego w bazie danych.
W systemie członkostwa SQL użyto skrótu PasswordHash, PasswordSalt i PasswordFormat w celu utworzenia skrótu hasła wprowadzonego przez użytkowników podczas rejestrowania lub zmiany hasła. Podczas migracji wszystkie trzy pola są przechowywane w kolumnie PasswordHash w tabeli AspNetUser oddzielonej znakiem '|'. Gdy użytkownik loguje się i hasło ma te pola, używamy kryptografii członkostwa SQL do sprawdzania hasła; W przeciwnym razie używamy domyślnej kryptografii systemu tożsamości do zweryfikowania hasła. Dzięki temu starzy użytkownicy nie musieliby zmieniać swoich haseł po przeprowadzeniu migracji aplikacji.
Zadeklaruj konstruktor dla klasy UserManager i przekaż go jako element SQLPasswordHasher do właściwości w konstruktorze.
public UserManager() : base(new UserStore<User>(new ApplicationDbContext())) { this.PasswordHasher = new SQLPasswordHasher(); }
Tworzenie nowych stron zarządzania kontami
Następnym krokiem migracji jest dodanie stron zarządzania kontami, które umożliwią użytkownikowi zarejestrowanie się i zalogowanie. Stare strony konta z członkostwa SQL używają kontrolek, które nie działają z nowym systemem tożsamości. Aby dodać nowe strony zarządzania użytkownikami, wykonaj czynności opisane w samouczku pod tym linkiemhttps://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-project, zaczynając od kroku "Dodawanie Web Forms do rejestrowania użytkowników w aplikacji", ponieważ projekt został już utworzony i dodano pakiety NuGet.
Musimy wprowadzić pewne zmiany w przykładzie, aby pracować z projektem, który mamy tutaj.
Kod Register.aspx.cs i Login.aspx.cs za klasami korzysta z
UserManager
pakietów Identity, aby utworzyć użytkownika. W tym przykładzie użyj menedżera użytkowników dodanego w folderze Models, wykonując kroki wymienione wcześniej.Użyj klasy User utworzonej zamiast klasy IdentityUser w plikach Register.aspx.cs i Login.aspx.cs za klasami. Spowoduje to wpięcie w naszej niestandardowej klasie użytkownika do systemu tożsamości.
Część do utworzenia bazy danych można pominąć.
Deweloper musi ustawić identyfikator ApplicationId dla nowego użytkownika, aby był zgodny z bieżącym identyfikatorem aplikacji. Można to zrobić, wykonując zapytanie dotyczące identyfikatora ApplicationId dla tej aplikacji, zanim obiekt użytkownika zostanie utworzony w klasie Register.aspx.cs i ustawić go przed utworzeniem użytkownika.
Przykład:
Zdefiniuj metodę na stronie Register.aspx.cs, aby wysłać zapytanie do tabeli aspnet_Applications i pobrać identyfikator aplikacji zgodnie z nazwą aplikacji
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(); } }
Teraz ustaw tę wartość w obiekcie użytkownika
var currentApplicationId = GetApplicationID(); User user = new User() { UserName = Username.Text, ApplicationId=currentApplicationId, …};
Użyj starej nazwy użytkownika i hasła, aby zalogować istniejącego użytkownika. Użyj strony Rejestrowanie, aby utworzyć nowego użytkownika. Sprawdź również, czy użytkownicy są w rolach zgodnie z oczekiwaniami.
Przenoszenie do systemu tożsamości pomaga użytkownikowi dodać do aplikacji protokół Open Authentication (OAuth). Zapoznaj się z przykładem w tym miejscu , w którym włączono uwierzytelnianie OAuth.
Następne kroki
W tym samouczku pokazano, jak przenosić użytkowników z członkostwa SQL w usłudze ASP.NET Identity, ale nie portowaliśmy danych profilu. W następnym samouczku omówimy przenoszenie danych profilu z członkostwa SQL do nowego systemu tożsamości.
Możesz zostawić opinię w dolnej części tego artykułu.
Dzięki Tomowi Dykstra i Rickowi Andersonowi do przejrzenia artykułu.