# Migrate from ASP.NET Membership authentication to ASP.NET Core 2.0 Identity
By [Isaac Levin](https://isaaclevin.com)
This article demonstrates migrating the database schema for ASP.NET apps using Membership authentication to ASP.NET Core 2.0 Identity.
> [!NOTE]
> This document provides the steps needed to migrate the database schema for ASP.NET Membership-based apps to the database schema used for ASP.NET Core Identity. For more information about migrating from ASP.NET Membership-based authentication to ASP.NET Identity, see [Migrate an existing app from SQL Membership to ASP.NET Identity](/aspnet/identity/overview/migrations/migrating-an-existing-website-from-sql-membership-to-aspnet-identity). For more information about ASP.NET Core Identity, see [Introduction to Identity on ASP.NET Core](xref:security/authentication/identity).
## Review of Membership schema
Prior to ASP.NET 2.0, developers were tasked with creating the entire authentication and authorization process for their apps. With ASP.NET 2.0, Membership was introduced, providing a boilerplate solution to handling security within ASP.NET apps. Developers were now able to bootstrap a schema into a SQL Server database with the [aspnet_regsql.exe](https://msdn.microsoft.com/library/ms229862.aspx) command. After running this command, the following tables were created in the database.
To migrate existing apps to ASP.NET Core 2.0 Identity, the data in these tables needs to be migrated to the tables used by the new Identity schema.
## ASP.NET Core Identity 2.0 schema
ASP.NET Core 2.0 follows the [Identity](/aspnet/identity/index) principle introduced in ASP.NET 4.5. Though the principle is shared, the implementation between the frameworks is different, even between versions of ASP.NET Core (see [Migrate authentication and Identity to ASP.NET Core 2.0](xref:migration/1x-to-2x/index)).
The fastest way to view the schema for ASP.NET Core 2.0 Identity is to create a new ASP.NET Core 2.0 app. Follow these steps in Visual Studio 2017:
* Create a new **ASP.NET Core Web Application** and name the project *CoreIdentitySample*.
* Select **ASP.NET Core 2.0** in the dropdown and then select **Web Application**. This template produces a [Razor Pages](xref:razor-pages/index) app. Before clicking **OK**, click **Change Authentication**.
* Choose **Individual User Accounts** for the Identity templates. Finally, click **OK**, then **OK**. Visual Studio creates a project using the ASP.NET Core Identity template.
ASP.NET Core 2.0 Identity uses [Entity Framework Core](/ef/core) to interact with the database storing the authentication data. In order for the newly created app to work, there needs to be a database to store this data. After creating a new app, the fastest way to inspect the schema in a database environment is to create the database using Entity Framework migrations. This process creates a database, either locally or elsewhere, which mimics that schema. Review the preceding documentation for more information.
To create a database with the ASP.NET Core Identity schema, run the `Update-Database` command in Visual Studio's**Package Manager Console**(PMC) window—it's located at**Tools**>**NuGet Package Manager**>**Package Manager Console**. PMC supports running Entity Framework commands.
Entity Framework commands use the connection string for the database specified in *appsettings.json*. The following connection string targets a database on *localhost* named *asp-net-core-identity*. In this setting, Entity Framework is configured to use the `DefaultConnection` connection string.
This command builds the database specified with the schema and any data needed for app initialization. The following image depicts the table structure that's created with the preceding steps.
There are subtle differences in the table structures and fields for both Membership and ASP.NET Core Identity. The pattern has changed substantially for authentication/authorization with ASP.NET and ASP.NET Core apps. The key objects that are still used with Identity are *Users* and *Roles*. Here are mapping tables for *Users*, *Roles*, and *UserRoles*.
|`LockoutEnabled` | bit | `aspnet_Membership.IsLockedOut` | bit
> [!NOTE]
> Not all the field mappings resemble one-to-one relationships from Membership to ASP.NET Core Identity. The preceding table takes the default Membership User schema and maps it to the ASP.NET Core Identity schema. Any other custom fields that were used for Membership need to be mapped manually. In this mapping, there's no map for passwords, as both password criteria and password salts don't migrate between the two. **It's recommended to leave the password as null and to ask users to reset their passwords.** In ASP.NET Core Identity, `LockoutEnd` should be set to some date in the future if the user is locked out. This is shown in the migration script.
Reference the preceding mapping tables when creating a migration script for *Users* and *Roles*. The following example assumes you have two databases on a database server. One database contains the existing ASP.NET Membership schema and data. The other database was created using steps described earlier. Comments are included inline for more details.
```sql
-- THIS SCRIPT NEEDS TO RUN FROM THE CONTEXT OF THE MEMBERSHIP DB
BEGIN TRANSACTION MigrateUsersAndRoles
use aspnetdb
-- INSERT USERS
INSERT INTO coreidentity.dbo.aspnetusers
(id,
username,
normalizedusername,
passwordhash,
securitystamp,
emailconfirmed,
phonenumber,
phonenumberconfirmed,
twofactorenabled,
lockoutend,
lockoutenabled,
accessfailedcount,
email,
normalizedemail)
SELECT aspnet_users.userid,
aspnet_users.username,
aspnet_users.loweredusername,
--Creates an empty password since passwords don't map between the two schemas
--EmailConfirmed is set when a new user is created and confirmed via email. Users must have this set during migration to ensure they're able to reset passwords.
1,
aspnet_users.mobilealias,
CASE
WHEN aspnet_Users.MobileAlias is null THEN 0
ELSE 1
END,
--2-factor Auth likely wasn't setup in Membership for users, so setting as false.
0,
CASE
--Setting lockout date to time in the future (1000 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,
aspnet_membership.loweredemail
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 coreidentity.dbo.aspnetusers
ON aspnet_membership.userid = aspnetusers.id
WHERE aspnetusers.id IS NULL
-- INSERT ROLES
INSERT INTO coreIdentity.dbo.aspnetroles(id,name)
SELECT roleId,rolename
FROM aspnet_roles;
-- INSERT USER ROLES
INSERT INTO coreidentity.dbo.aspnetuserroles(userid,roleid)
SELECT userid,roleid
FROM aspnet_usersinroles;
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION MigrateUsersAndRoles
RETURN
END
COMMIT TRANSACTION MigrateUsersAndRoles
```
After completion of this script, the ASP.NET Core Identity app created earlier is populated with Membership users. Users need to change their passwords before logging in.
> [!NOTE]
> If the Membership system had users with user names that didn't match their email address, changes are required to the app created earlier to accommodate this. The default template expects `UserName` and `Email` to be the same. For situations in which they're different, the login process needs to be modified to use `UserName` instead of `Email`.
In the `PageModel` of the Login Page, located at *Pages\Account\Login.cshtml.cs*, remove the `[EmailAddress]` attribute from the *Email* property. Rename it to *UserName*. This requires a change wherever `EmailAddress` is mentioned, in the *View* and *PageModel*. The result looks like the following:
![Fixed Login](identity/_static/fixed-login.png)
## Next steps
In this tutorial, you learned how to port users from SQL membership to ASP.NET Core 2.0 Identity. For more information regarding ASP.NET Core Identity, see [Introduction to Identity](xref:security/authentication/identity).