Миграция внутренней аутентификации в ASP.NET Core Identity

Я работаю над обновлением очень старого сайта с классического ASP до ASP.NET Core. Часть этого состоит в том, чтобы перенести пользователей (чьи пароли хранятся в незашифрованном виде, естественно) в Identity. Мы используем проект модульного тестирования для управления миграцией, но этот проект, понятно, не может получить доступ к Identity.

Какой лучший вариант здесь? Основная проблема, которую я вижу, - это получение паролей в правильном формате, но я думаю, что я мог бы взглянуть на источник удостоверения ASP.NET и имитировать функциональность, чтобы правильно хэшировать все в процессе миграции. Есть ли способ лучше?

2 ответа

Алгоритм хеширования, используемый ASP.NET Identity 3, здесь. Однако запустить ASP.NET Idetity нелегко, если вы не скопируете его зависимости в свой проект.

HashPasswordV3

private static byte[] HashPasswordV3(string password, 
   RandomNumberGenerator rng, KeyDerivationPrf prf, 
   int iterCount, int saltSize, int numBytesRequested)
    {
    // Produce a version 3 (see comment above) text hash.
    byte[] salt = new byte[saltSize];
    rng.GetBytes(salt);
    byte[] subkey = KeyDerivation.Pbkdf2(
        password, salt, prf, iterCount, numBytesRequested);

    var outputBytes = new byte[13 + salt.Length + subkey.Length];
    outputBytes[0] = 0x01; // format marker
    WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
    WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
    WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
    Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
    Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
    return outputBytes;
}

VerifyHashedPasswordV3

private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, out int iterCount)
{
    iterCount = default(int);

    try
    {
        // Read header information
        KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1);
        iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5);
        int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9);

        // Read the salt: must be >= 128 bits
        if (saltLength < 128 / 8)
        {
            return false;
        }
        byte[] salt = new byte[saltLength];
        Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length);

        // Read the subkey (the rest of the payload): must be >= 128 bits
        int subkeyLength = hashedPassword.Length - 13 - salt.Length;
        if (subkeyLength < 128 / 8)
        {
            return false;
        }
        byte[] expectedSubkey = new byte[subkeyLength];
        Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

        // Hash the incoming password and verify it
        byte[] actualSubkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength);
        return ByteArraysEqual(actualSubkey, expectedSubkey);
    }
    catch
    {
        // This should never occur except in the case of a malformed payload, where
        // we might go off the end of the array. Regardless, a malformed payload
        // implies verification failed.
        return false;
    }
}

Пароли в виде простого текста, так что вы можете просто загрузить каждого пользователя из текущей базы данных и добавить его в новую базу данных, используя UserManager класс в идентичности.

UserManager класс имеет CreateAsync метод, который принимает пароль, и он будет обрабатывать хеширование для вас.

Пример:

var user = new IdentityUser // or whatever your user class is
{
    UserName = userName,
    Email = email,
    // set other required properties
};

var result = await userManager.CreateAsync(user, password);

Я бы порекомендовал запустить его вручную в отдельной программе как разовую задачу. Вы не хотите, чтобы эта процедура жила в новом приложении.

Другие вопросы по тегам