【问题标题】:Migrating in-house authentication to ASP.NET Core Identity将内部身份验证迁移到 ASP.NET Core Identity
【发布时间】:2017-07-22 23:28:12
【问题描述】:

我正在努力将一个非常旧的网站从经典 ASP 升级到 ASP.NET Core。其中一部分是将用户(其密码自然地以明文形式存储)迁移到身份中。我们正在使用单元测试项目来处理迁移,但该项目无法访问身份,这是可以理解的。

这里最好的选择是什么?我看到的主要问题是将密码转换为正确的格式,但我认为我可以查看 ASP.NET Identity 的来源并模仿功能以正确散列迁移中的所有内容。有没有更好的办法?

【问题讨论】:

    标签: asp.net-core asp.net-core-identity


    【解决方案1】:

    ASP.NET Identity 3 使用的哈希算法是here。但是,容易在 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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      密码是纯文本的,因此您可以简单地从当前数据库加载每个用户,然后使用 Identity 中的 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);
      

      我建议在单独的程序中手动将其作为一次性任务运行。您不希望此过程存在于新应用程序中。

      【讨论】:

        猜你喜欢
        • 2018-02-15
        • 1970-01-01
        • 2018-04-05
        • 2020-05-25
        • 2018-07-06
        • 1970-01-01
        • 2021-03-15
        • 2018-12-30
        • 2017-03-18
        相关资源
        最近更新 更多