Compartir a través de


Migración de la autenticación de pertenencia de ASP.NET a ASP.NET Core 2.0 Identity

Por Isaac Levin

En este artículo se muestra cómo migrar el esquema de base de datos para ASP.NET aplicaciones mediante la autenticación de pertenencia a ASP.NET Core 2.0 Identity.

Nota:

En este documento se proporcionan los pasos necesarios para migrar el esquema de base de datos para ASP.NET aplicaciones basadas en pertenencia al esquema de base de datos usado para ASP.NET Core Identity. Para obtener más información sobre la migración de la autenticación basada en membresía de ASP.NET a ASP.NET Identity, consulte Migración de una aplicación existente de Membresía de SQL a ASP.NET Identity. Para obtener más información sobre ASP.NET Core Identity, consulte Introducción a Identity en ASP.NET Core.

Revisión del esquema de pertenencia

Antes de ASP.NET 2.0, a los desarrolladores se les encargaba crear todo el proceso de autenticación y autorización para sus aplicaciones. Con ASP.NET 2.0, se introdujo la pertenencia, proporcionando una solución reutilizable para controlar la seguridad dentro de las aplicaciones de ASP.NET. Los desarrolladores ahora podían iniciar un esquema en una base de datos de SQL Server con la herramienta de registro de ASP.NET SQL Server (Aspnet_regsql.exe) (ya no se admite). Después de ejecutar este comando, se crearon las tablas siguientes en la base de datos.

Tablas de pertenencia

Para migrar aplicaciones existentes a ASP.NET Core 2.0 Identity, los datos de estas tablas deben migrarse a las tablas que usa el nuevo esquema Identity.

Esquema de ASP.NET Core Identity 2.0

ASP.NET Core 2.0 se rige por el Identity principio introducido en ASP.NET 4.5. Aunque el principio se comparte, la implementación entre los marcos es diferente, incluso entre las versiones de ASP.NET Core (consulte Migración de autenticación y de Identity a ASP.NET Core 2.0).

La forma más rápida de ver el esquema de ASP.NET Core 2.0 Identity es crear una nueva aplicación de ASP.NET Core 2.0. Siga estos pasos en Visual Studio 2017:

  1. Seleccione Archivo>Nuevo>Proyecto.

  2. Crea un nuevo proyecto de aplicación web de ASP.NET Core denominado CoreIdentitySample.

  3. Seleccione ASP.NET Core 2.0 en la lista desplegable y, luego, Aplicación web. Esta plantilla genera una aplicación de Razor Pages. Antes de hacer clic en Aceptar, haga clic en Cambiar Autenticación.

  4. Elija Cuentas de usuario individuales para las plantillas de Identity. Por último, haga clic en Aceptar y, a continuación, en Aceptar. Visual Studio crea un proyecto mediante la plantilla ASP.NET Core Identity .

  5. Seleccione Herramientas>Administrador de paquetes NuGet>Consola del administrador de paquetes para abrir la ventana de la Consola del administrador de paquetes (PMC).

  6. Vaya a la raíz del proyecto en la PMC y ejecute el comando Update-Database de Entity Framework (EF) Core.

    ASP.NET Core 2.0 Identity usa EF Core para interactuar con la base de datos que almacena los datos de autenticación. Para que la aplicación recién creada funcione, debe haber una base de datos para almacenar estos datos. Después de crear una nueva aplicación, la forma más rápida de inspeccionar el esquema en un entorno de base de datos es crear la base de datos mediante EF Core Migraciones. Este proceso crea una base de datos, ya sea localmente o en otro lugar, que imita ese esquema. Revise la documentación anterior para obtener más información.

    Los comandos EF Core usan la cadena de conexión para la base de datos especificada en appsettings.json. La siguiente cadena de conexión tiene como destino una base de datos en localhost denominada asp-net-core-identity. En esta configuración, EF Core se establece para usar la cadena de conexión DefaultConnection.

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=localhost;Database=aspnet-core-identity;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
    

Advertencia

En este artículo se muestra el uso de cadena de conexión. Con una base de datos local, el usuario no tiene que autenticarse, pero en producción, cadena de conexión a veces incluye una contraseña para autenticarse. Una credencial de contraseña de propietario de recursos (ROPC) es un riesgo de seguridad que se debe evitar en las bases de datos de producción. Las aplicaciones de producción deben usar el flujo de autenticación más seguro disponible. Para obtener más información sobre la autenticación de aplicaciones implementadas para probar o entornos de producción, consulte Flujos de autenticación seguros.

  1. Seleccione Ver>Explorador de objetos de SQL Server. Expanda el nodo correspondiente al nombre de la base de datos especificado en la propiedad ConnectionStrings:DefaultConnection de appsettings.json.

    El comando Update-Database creó la base de datos especificada con el esquema y los datos necesarios para la inicialización de la aplicación. En la imagen siguiente se muestra la estructura de tabla que se crea con los pasos anteriores.

    Identity Tablas

Migración del esquema

Existen diferencias sutiles en las estructuras de tabla y los campos de pertenencia y ASP.NET Core Identity. El patrón ha cambiado sustancialmente para la autenticación y autorización con ASP.NET y ASP.NET Core aplicaciones. Los objetos clave que todavía se usan con Identity son Usuarios y Roles. Estas son las tablas de asignación para Usuarios, Roles y UserRoles.

Usuarios

Identity
Columna (dbo.AspNetUsers)
Tipo Membership
Columna (dbo.aspnet_Users / dbo.aspnet_Membership)
Tipo
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 no se asigna a LockoutEnabled. IsLockedOut se establece si un usuario tuvo demasiados inicios de sesión fallidos y se bloquea durante un tiempo determinado. LockoutEnabled permite bloquear a un usuario con demasiados intentos fallidos de inicio de sesión. Cuando el usuario tiene demasiados intentos de inicio de sesión erróneos, LockoutEnd se establece en una fecha en el futuro y el usuario no puede iniciar sesión hasta esa fecha. Si LockoutEnabled es FALSE, el usuario nunca se bloquea para demasiados intentos de inicio de sesión erróneos. Según OWASP, el bloqueo temporal de la cuenta después de varios intentos fallidos es un objetivo demasiado simple para los ataques DoS contra usuarios legítimos.

Para obtener más información sobre el bloqueo, consulte Pruebas OWASP para el mecanismo de bloqueo débil.

Las aplicaciones que migren a Identity que deseen habilitar el bloqueo de inicio de sesión fallido deben establecer LockoutEnabled en TRUE como parte de la migración.

Nota:

No todas las asignaciones de campos se asemejan a las relaciones uno a uno de pertenencia a ASP.NET Core Identity. La tabla anterior toma el esquema de usuario de pertenencia predeterminado y lo asigna al esquema de ASP.NET Core Identity . Cualquier otro campo personalizado que se usó para la pertenencia debe asignarse manualmente. En esta asignación, no hay ningún mapa para las contraseñas, ya que los criterios de contraseña y las sales de contraseña no se migran entre los dos. Se recomienda dejar la contraseña como null y pedir a los usuarios que restablezcan sus contraseñas. En ASP.NET Core Identity, LockoutEnd debe establecerse en alguna fecha en el futuro si el usuario está bloqueado. Esto se muestra en el script de migración.

Roles

Identity
Columna (dbo.AspNetRoles)
Tipo Membership
Columna (dbo.aspnet_Roles)
Tipo
Id string RoleId string
Name string RoleName string
NormalizedName string LoweredRoleName string

Roles de usuario

Identity
Columna (dbo.AspNetUserRoles)
Tipo Membership
Columna (dbo.aspnet_UsersInRoles)
Tipo
RoleId string RoleId string
UserId string UserId string

Haga referencia a las tablas de asignación anteriores al crear un script de migración para Usuarios y Roles. En el ejemplo siguiente se supone que tiene dos bases de datos en un servidor de bases de datos. Una base de datos contiene los datos y el esquema de pertenencia de ASP.NET existentes. La otra base de datos CoreIdentitySample se creó siguiendo los pasos descritos anteriormente. Los comentarios se incluyen en línea para obtener más detalles.

-- 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

Después de completar el script anterior, la aplicación ASP.NET Core Identity creada anteriormente se rellena con usuarios de pertenencia. Los usuarios deben cambiar sus contraseñas antes de iniciar sesión.

Nota:

Si el sistema de pertenencia tenía usuarios con nombres de usuario que no coincidieron con su dirección de correo electrónico, se requieren cambios en la aplicación creada anteriormente para dar cabida a esto. La plantilla predeterminada espera que UserName y Email sean los mismos. Para situaciones en las que son diferentes, el proceso de inicio de sesión debe modificarse para usar UserName en lugar de Email.

En PageModel de la página de inicio de sesión, ubicado en, quite el atributo [EmailAddress] de la propiedad Email. Cambie el nombre a UserName. Esto requiere un cambio dondequiera que se mencione EmailAddress, en la Vista y en PageModel. El resultado será similar al siguiente:

Inicio de sesión fijo

Pasos siguientes

En este tutorial, ha aprendido a migrar usuarios de la pertenencia de SQL a ASP.NET Core 2.0 Identity. Para obtener más información sobre ASP.NET Core Identity, consulte Introducción a Identity.