• Blogs
  • /
  • .NET tricks
  • /
  • ASP.NET Identity: Migrating users' passwords from ASP.NET Membership

ASP.NET Identity: Migrating users' passwords from ASP.NET Membership

This is a third part of the series of articles about some not-so-well-known features and tricks in ASP.NET Identity. Here are you can find the first and the second parts.

Problem

This task usually appears when you need to transfer your old MVC web application to ASP.NET Core. If you use MVC version 3 or 4 and your application provides a user authentication service, then most likely this part is done with old ASP.NET Membership library.

So, imagine you have a bunch of users, each of them has some password and the hash of that password stored in some database. Now you need to transfer all your current users to the new system built with ASP.NET Core. Of course, it's not a big problem to transfer their names, addresses and other information. The problem is in those password hashes. ASP.NET Core Identity uses another hashing algorithm so all current users will not be able to access the system with their old passwords - the hashes will not match.

Solution

The solution is rather simple: we need to rewrite the default hashing service in ASP.NET Core Identity and make it "understand" both the old and new hashes.

Here is our class which implements IPassowrdHasher interface:

public class PasswordHasherWithOldMembershipSupport : IPasswordHasher<ApplicationUser>
{
	//an instance of the default password hasher
	IPasswordHasher<ApplicationUser> _identityPasswordHasher = new PasswordHasher<ApplicationUser>();

	//Hashes the password using old algorithm from the days of ASP.NET Membership
	internal static string HashPasswordInOldFormat(string password) 
	{
		var sha1 = new SHA1CryptoServiceProvider();
		var data = Encoding.ASCII.GetBytes(password);
		var sha1data = sha1.ComputeHash(data);
		return Convert.ToBase64String(sha1data);
	}

	//the passwords of the new users will be hashed with new algorithm
	public string HashPassword(ApplicationUser user, string password) {
		return _identityPasswordHasher.HashPassword(user, password);
	}

	public PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, 
				string hashedPassword, string providedPassword) 
	{
		string pwdHash2 = HashPasswordInOldFormat(providedPassword);
		

		if (hashedPassword == pwdHash2) {
			//first we check the hashed password with "old" hash
			return PasswordVerificationResult.Success;
		}
		else {
			//if old hash doesn't work - use the default approach 
			return _identityPasswordHasher.VerifyHashedPassword(user, hashedPassword, providedPassword);
		}
	}
}

After that we just need to register our new IPasswordHasher implementation in the DI container:

//Startup.cs
.   .   .   .   .   .
public void ConfigureServices(IServiceCollection services)
{
    .   .   .   .   .   .
 
    services.AddSingleton<IPasswordHasher<ApplicationUser>, PasswordHasherWithOldMembershipSupport>();
}

Recent posts

Supported by EasyQuery

EasyQuery is a multi-platform solution that lets you embedding ad-hoc reporting or advanced search functionality to your application