Eseguire la migrazione dall'autenticazione di appartenenza ASP.NET a ASP.NET Core 2.0 Identity

Di Isaac Levin

Questo articolo illustra la migrazione dello schema del database per le app ASP.NET usando l'autenticazione di appartenenza a ASP.NET Core 2.0 Identity.

Nota

Questo documento illustra i passaggi necessari per eseguire la migrazione dello schema del database per ASP.NET app basate sull'appartenenza allo schema del database usato per ASP.NET Core Identity. Per altre informazioni sulla migrazione dall'autenticazione basata sull'appartenenza a ASP.NET a ASP.NET Identity, vedere Eseguire la migrazione di un'app esistente dall'appartenenza SQL a ASP.NET Identity. Per altre informazioni su ASP.NET Core Identity, vedere Introduzione a Identity in ASP.NET Core.

Revisione dello schema di appartenenza

Prima di ASP.NET 2.0, gli sviluppatori dovevano creare l'intero processo di autenticazione e autorizzazione per le app. Con ASP.NET 2.0, è stata introdotta l'appartenenza, fornendo una soluzione boilerplate per gestire la sicurezza all'interno delle app ASP.NET. Gli sviluppatori sono ora in grado di eseguire il bootstrap di uno schema in un database di SQL Server con lo strumento di registrazione di SQL Server ASP.NET () (Aspnet_regsql.exenon più supportato). Dopo aver eseguito questo comando, nel database sono state create le tabelle seguenti.

Membership Tables

Per eseguire la migrazione di app esistenti a ASP.NET Core 2.0 Identity, è necessario eseguire la migrazione dei dati in queste tabelle alle tabelle usate dal nuovo Identity schema.

schema ASP.NET Core Identity 2.0

ASP.NET Core 2.0 segue il Identity principio introdotto in ASP.NET 4.5. Anche se il principio è condiviso, l'implementazione tra i framework è diversa, anche tra le versioni di ASP.NET Core (vedere Eseguire la migrazione dell'autenticazione e Identity a ASP.NET Core 2.0).

Il modo più rapido per visualizzare lo schema per ASP.NET Core 2.0 Identity consiste nel creare una nuova app ASP.NET Core 2.0. Seguire questa procedura in Visual Studio 2017:

  1. Selezionare File>New (Nuovo) >Project (Progetto).

  2. Creare un nuovo progetto di applicazione Web core ASP.NET denominato CoreIdentitySample.

  3. Selezionare ASP.NET Core 2.0 nell'elenco a discesa e quindi selezionare Applicazione Web. Questo modello produce un'app Razor Pages . Prima di fare clic su OK, fare clic su Modifica autenticazione.

  4. Scegliere Account utente singoli per i Identity modelli. Infine, fare clic su OK, quindi su OK. Visual Studio crea un progetto usando il modello ASP.NET Core Identity .

  5. Selezionare Strumenti>NuGet Gestione pacchetti> Gestione pacchetti Console per aprire la finestra Gestione pacchetti Console (PMC).

  6. Passare alla radice del progetto in PMC ed eseguire il comando Entity Framework (EF) CoreUpdate-Database .

    ASP.NET Core 2.0 Identity usa EF Core per interagire con il database che archivia i dati di autenticazione. Affinché l'app appena creata funzioni, è necessario che sia presente un database per archiviare questi dati. Dopo aver creato una nuova app, il modo più rapido per esaminare lo schema in un ambiente di database consiste nel creare il database usando EF Core Migrazioni. Questo processo crea un database, localmente o altrove, che simula tale schema. Per altre informazioni, vedere la documentazione precedente.

    EF CoreI comandi usano il stringa di connessione per il database specificato in appsettings.json. Il stringa di connessione seguente è destinato a un database in localhost denominato asp-net-core-identity. In questa impostazione EF Core è configurato per l'uso del DefaultConnection stringa di connessione.

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=localhost;Database=aspnet-core-identity;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
    
  7. Selezionare Visualizza>Esplora oggetti SQL Server. Espandere il nodo corrispondente al nome del database specificato nella ConnectionStrings:DefaultConnection proprietà di appsettings.json.

    Il Update-Database comando ha creato il database specificato con lo schema ed eventuali dati necessari per l'inizializzazione dell'app. L'immagine seguente illustra la struttura della tabella creata con i passaggi precedenti.

    Identity Tables

Migrazione dello schema

Esistono piccole differenze nelle strutture di tabella e nei campi sia per Appartenenza che per ASP.NET Core Identity. Il modello è stato modificato in modo sostanziale per l'autenticazione/autorizzazione con le app ASP.NET e ASP.NET Core. Gli oggetti chiave ancora usati con Identity sono Utenti e Ruoli. Ecco le tabelle di mapping per Utenti, Ruoli e UserRoles.

Utenti

Identity
(dbo.AspNetUsers) colonna
Digita Appartenenze
(dbo.aspnet_Users / dbo.aspnet_Membership) colonna
Digita
Id string aspnet_Users.UserId string
UserName string aspnet_Users.UserName string
Email string aspnet_Membership.Email string
NormalizedUserName string aspnet_Users.LoweredUserName string
NormalizedEmail string aspnet_Membership.LoweredEmail string
PhoneNumber string aspnet_Users.MobileAlias string
LockoutEnabled bit aspnet_Membership.IsLockedOut bit

IsLockedOut non esegue il mapping a LockoutEnabled. IsLockedOut è impostato se un utente ha avuto troppi accessi non riusciti ed è bloccato per un periodo di tempo impostato. LockoutEnabled consente di bloccare un utente con troppi tentativi di accesso non riusciti. Quando l'utente ha troppi tentativi di accesso non riusciti, LockoutEnd viene impostato su una data futura e l'utente non può accedere fino a tale data. Se LockoutEnabled è false, un utente non viene mai bloccato per troppi tentativi di accesso non riusciti. Per OWASP, il blocco temporaneo dell'account dopo diversi tentativi non riusciti è troppo semplice di una destinazione per gli attacchi DoS contro gli utenti legittimi.

Per altre informazioni sul blocco, vedere Test OWASP per il meccanismo di blocco debole.

Le app che eseguono la migrazione a Identity che desiderano abilitare il blocco di accesso non riuscito devono essere impostate su LockoutEnabled true come parte della migrazione.

Nota

Non tutti i mapping dei campi sono simili a relazioni uno-a-uno dall'appartenenza a ASP.NET Core Identity. La tabella precedente accetta lo schema user di appartenenza predefinito e lo esegue il mapping allo schema ASP.NET Core Identity . Tutti gli altri campi personalizzati usati per l'appartenenza devono essere mappati manualmente. In questo mapping non è disponibile alcuna mappa per le password, poiché i criteri di password e i salti delle password non eseguono la migrazione tra i due. È consigliabile lasciare la password null e chiedere agli utenti di reimpostare le password. In ASP.NET Core IdentityLockoutEnd deve essere impostato su una data futura se l'utente è bloccato. Questo è illustrato nello script di migrazione.

Ruoli

Identity
(dbo.AspNetRoles) colonna
Digita Appartenenze
(dbo.aspnet_Roles) colonna
Digita
Id string RoleId string
Name string RoleName string
NormalizedName string LoweredRoleName string

User Roles

Identity
(dbo.AspNetUserRoles) colonna
Digita Appartenenze
(dbo.aspnet_UsersInRoles) colonna
Digita
RoleId string RoleId string
UserId string UserId string

Fare riferimento alle tabelle di mapping precedenti durante la creazione di uno script di migrazione per utenti e ruoli. Nell'esempio seguente si presuppone che siano presenti due database in un server di database. Un database contiene lo schema e i dati di appartenenza ASP.NET esistenti. L'altro database di esempio coreIdentityè stato creato usando i passaggi descritti in precedenza. I commenti sono inclusi inline per altri dettagli.

-- THIS SCRIPT NEEDS TO RUN FROM THE CONTEXT OF THE MEMBERSHIP DB
BEGIN TRANSACTION MigrateUsersAndRoles
USE aspnetdb

-- INSERT USERS
INSERT INTO CoreIdentitySample.dbo.AspNetUsers
            (Id,
             UserName,
             NormalizedUserName,
             PasswordHash,
             SecurityStamp,
             EmailConfirmed,
             PhoneNumber,
             PhoneNumberConfirmed,
             TwoFactorEnabled,
             LockoutEnd,
             LockoutEnabled,
             AccessFailedCount,
             Email,
             NormalizedEmail)
SELECT aspnet_Users.UserId,
       aspnet_Users.UserName,
       -- The NormalizedUserName value is upper case in ASP.NET Core Identity
       UPPER(aspnet_Users.UserName),
       -- Creates an empty password since passwords don't map between the 2 schemas
       '',
       /*
        The SecurityStamp token is used to verify the state of an account and
        is subject to change at any time. It should be initialized as a new ID.
       */
       NewID(),
       /*
        EmailConfirmed is set when a new user is created and confirmed via email.
        Users must have this set during migration to reset passwords.
       */
       1,
       aspnet_Users.MobileAlias,
       CASE
         WHEN aspnet_Users.MobileAlias IS NULL THEN 0
         ELSE 1
       END,
       -- 2FA likely wasn't setup in Membership for users, so setting as false.
       0,
       CASE
         -- Setting lockout date to time in the future (1,000 years)
         WHEN aspnet_Membership.IsLockedOut = 1 THEN Dateadd(year, 1000,
                                                     Sysutcdatetime())
         ELSE NULL
       END,
       aspnet_Membership.IsLockedOut,
       /*
        AccessFailedAccount is used to track failed logins. This is stored in
        Membership in multiple columns. Setting to 0 arbitrarily.
       */
       0,
       aspnet_Membership.Email,
       -- The NormalizedEmail value is upper case in ASP.NET Core Identity
       UPPER(aspnet_Membership.Email)
FROM   aspnet_Users
       LEFT OUTER JOIN aspnet_Membership
                    ON aspnet_Membership.ApplicationId =
                       aspnet_Users.ApplicationId
                       AND aspnet_Users.UserId = aspnet_Membership.UserId
       LEFT OUTER JOIN CoreIdentitySample.dbo.AspNetUsers
                    ON aspnet_Membership.UserId = AspNetUsers.Id
WHERE  AspNetUsers.Id IS NULL

-- INSERT ROLES
INSERT INTO CoreIdentitySample.dbo.AspNetRoles(Id, Name)
SELECT RoleId, RoleName
FROM aspnet_Roles;

-- INSERT USER ROLES
INSERT INTO CoreIdentitySample.dbo.AspNetUserRoles(UserId, RoleId)
SELECT UserId, RoleId
FROM aspnet_UsersInRoles;

IF @@ERROR <> 0
  BEGIN
    ROLLBACK TRANSACTION MigrateUsersAndRoles
    RETURN
  END

COMMIT TRANSACTION MigrateUsersAndRoles

Al termine dello script precedente, l'app ASP.NET Core Identity creata in precedenza viene popolata con Utenti di appartenenza. Gli utenti devono modificare le password prima di eseguire l'accesso.

Nota

Se il sistema di appartenenza aveva utenti con nomi utente che non corrispondono al proprio indirizzo di posta elettronica, le modifiche all'app create in precedenza sono necessarie per soddisfare questo problema. Il modello predefinito prevede UserName e Email deve essere lo stesso. Per le situazioni in cui sono diverse, il processo di accesso deve essere modificato in modo da usare UserName invece di Email.

Nell'oggetto PageModel della pagina di accesso, che si trova in , rimuovere l'attributo [EmailAddress] dalla proprietà Email . Rinominarlo in UserName. Ciò richiede una modifica ovunque EmailAddress venga menzionata, nella visualizzazione e nel modello di pagina. Il risultato è simile al seguente:

Fixed Login

Passaggi successivi

In questa esercitazione si è appreso come convertire gli utenti dall'appartenenza a SQL a ASP.NET Core 2.0 Identity. Per altre informazioni su ASP.NET Core Identity, vedere Introduzione a Identity.