不要使用自定义的 VerifyHashedPassword 方法。
从下面PasswordHasher的源代码中,我们可以看到VerifyHashedPassword()可以通过数据库中的hashedPassword和原始输入密码自动验证。
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
namespace Microsoft.AspNet.Identity
{
internal static class Crypto
{
private const int PBKDF2IterCount = 1000;
private const int PBKDF2SubkeyLength = 32;
private const int SaltSize = 16;
public static string HashPassword(string password)
{
if (password == null)
throw new ArgumentNullException("password");
byte[] salt;
byte[] bytes;
using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, 16, 1000))
{
salt = rfc2898DeriveBytes.Salt;
bytes = rfc2898DeriveBytes.GetBytes(32);
}
byte[] inArray = new byte[49];
Buffer.BlockCopy((Array) salt, 0, (Array) inArray, 1, 16);
Buffer.BlockCopy((Array) bytes, 0, (Array) inArray, 17, 32);
return Convert.ToBase64String(inArray);
}
public static bool VerifyHashedPassword(string hashedPassword, string password)
{
if (hashedPassword == null)
return false;
if (password == null)
throw new ArgumentNullException("password");
byte[] numArray = Convert.FromBase64String(hashedPassword);
if (numArray.Length != 49 || (int) numArray[0] != 0)
return false;
byte[] salt = new byte[16];
Buffer.BlockCopy((Array) numArray, 1, (Array) salt, 0, 16);
byte[] a = new byte[32];
Buffer.BlockCopy((Array) numArray, 17, (Array) a, 0, 32);
byte[] bytes;
using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, 1000))
bytes = rfc2898DeriveBytes.GetBytes(32);
return Crypto.ByteArraysEqual(a, bytes);
}
[MethodImpl(MethodImplOptions.NoOptimization)]
private static bool ByteArraysEqual(byte[] a, byte[] b)
{
if (object.ReferenceEquals((object) a, (object) b))
return true;
if (a == null || b == null || a.Length != b.Length)
return false;
bool flag = true;
for (int index = 0; index < a.Length; ++index)
flag &= (int) a[index] == (int) b[index];
return flag;
}
}
}
测试代码
public static User user = new User();
[Route("/")]
public IActionResult Index()
{
//register a user
if(user != null) {
//test data
user.Id = Guid.NewGuid();
user.UserName = "test";
user.Email = "test@x.com";
user.Password = "password";
var hasher = new Microsoft.AspNetCore.Identity.PasswordHasher<IdentityUser>();
IdentityUser identityUser = new IdentityUser(user.Id.ToString());
user.PasswordHash = hasher.HashPassword(identityUser, user.Password);
}
//... save user to DB
return View();
}
登录控制器
[HttpPost]
public IActionResult Login(LoginViewModel login)
{
if (ModelState.IsValid)
{
//... Here are codes get Id by email from DB
var hasher = new Microsoft.AspNetCore.Identity.PasswordHasher<IdentityUser>();
IdentityUser identityUser = new IdentityUser(user.Id.ToString());
if (PasswordVerificationResult.Failed == hasher.VerifyHashedPassword(identityUser,user.PasswordHash, login.Password))
ModelState.AddModelError("Password", "password is wrong");
}
else
ModelState.AddModelError("Email", "email or password invalid");
return PartialView("_LoginModalPartial", login);
}
结果测试