ASP.NET Identity PasswordHasher在每个请求上生成不同的哈希值

时间:2014-02-02 15:28:30

标签: c# asp.net entity-framework asp.net-mvc-5 asp.net-identity

我正在遇到一个我正在研究的解决方案的特殊问题。它使用ASP.NET身份系统和我自己构建的自定义实现来处理现有数据。直到昨天,它工作正常,但后来我不能再登录了。据我所知,看起来密码hasher在每个请求上产生不同的哈希值,其中的哈希值与存储在数据库中的哈希值匹配。

有什么我做错了才能实现这个目标吗?不确定这是否重要,但我正在研究从办公室电脑下载的解决方案的本地副本,因为RDP变得很烦人。它确实在本地工作,但我认为当我将数据库种子从基于对象的脚本更改为直接的SQL脚本时,它就停止了。考虑到我插入相同的值,不知道为什么会使它无效,但我在这里,无法进行身份验证。

更新

我正在使用的UserManager是通过Ninject在UserStore的实例中传递的。这是我UserStore的代码:

public class EmployeeStore : IQueryableUserStore<Employee, int>, IUserStore<Employee, int>, IUserPasswordStore<Employee, int>, IUserRoleStore<Employee, int>, IDisposable {
    private bool Disposed;
    private IDatabaseRepository<Role> RolesRepository { get; set; }
    private IDatabaseRepository<Employee> EmployeesRepository { get; set; }

    public EmployeeStore(
        IDatabaseRepository<Role> rolesRepository,
        IDatabaseRepository<Employee> employeesRepository) {
        this.RolesRepository = rolesRepository;
        this.EmployeesRepository = employeesRepository;
    }

    #region IQueryableUserStore Members
    public IQueryable<Employee> Users {
        get {
            return this.EmployeesRepository.Set;
        }
    }
    #endregion

    #region IUserStore Members
    public async Task CreateAsync(
        Employee employee) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        await this.EmployeesRepository.AddAndCommitAsync(employee);
    }

    public async Task DeleteAsync(
        Employee employee) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        await this.EmployeesRepository.RemoveAndCommitAsync(employee);
    }

    public Task<Employee> FindByIdAsync(
        int employeeId) {
        this.ThrowIfDisposed();

        return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
            u =>
                (u.Id == employeeId)));
    }

    public Task<Employee> FindByNameAsync(
        string userName) {
        this.ThrowIfDisposed();

        return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
            e =>
                (e.UserName == userName)));
    }

    public async Task UpdateAsync(
        Employee employee) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        await this.EmployeesRepository.CommitAsync();
    }
    #endregion

    #region IDisposable Members
    public void Dispose() {
        this.Dispose(true);

        GC.SuppressFinalize(this);
    }

    protected void Dispose(
        bool disposing) {
        this.Disposed = true;
    }

    private void ThrowIfDisposed() {
        if (this.Disposed) {
            throw new ObjectDisposedException(base.GetType().Name);
        }
    }
    #endregion

    #region IUserPasswordStore Members
    public Task<string> GetPasswordHashAsync(
        Employee employee) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        return Task.FromResult<string>(employee.PasswordHash);
    }

    public Task<bool> HasPasswordAsync(
        Employee employee) {
        return Task.FromResult<bool>(!String.IsNullOrEmpty(employee.PasswordHash));
    }

    public Task SetPasswordHashAsync(
        Employee employee,
        string passwordHash) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        employee.PasswordHash = passwordHash;

        return Task.FromResult<int>(0);
    }
    #endregion

    #region IUserRoleStore Members
    public Task AddToRoleAsync(
        Employee employee,
        string roleName) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        if (String.IsNullOrEmpty(roleName)) {
            throw new ArgumentNullException("roleName");
        }

        Role role = this.RolesRepository.FindSingleOrDefault(
            r =>
                (r.Name == roleName));

        if (role == null) {
            throw new InvalidOperationException("Role not found");
        }

        employee.Roles.Add(role);

        return Task.FromResult<int>(0);
    }

    public Task<IList<string>> GetRolesAsync(
        Employee employee) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        return Task.FromResult<IList<string>>(employee.Roles.Select(
            r =>
                r.Name).ToList());
    }

    public Task<bool> IsInRoleAsync(
        Employee employee,
        string roleName) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        if (String.IsNullOrEmpty(roleName)) {
            throw new ArgumentNullException("roleName");
        }

        return Task.FromResult<bool>(employee.Roles.Any(
            r =>
                (r.Name == roleName)));
    }

    public Task RemoveFromRoleAsync(
        Employee employee,
        string roleName) {
        this.ThrowIfDisposed();

        if (employee == null) {
            throw new ArgumentNullException("employee");
        }

        if (String.IsNullOrEmpty(roleName)) {
            throw new ArgumentNullException("roleName");
        }

        Role role = this.RolesRepository.FindSingleOrDefault(
            r =>
                (r.Name == roleName));

        if (role == null) {
            throw new InvalidOperationException("Role is null");
        }

        employee.Roles.Remove(role);

        return Task.FromResult<int>(0);
    }
    #endregion
}

这是我的登录控制器:

public sealed class SiteController : BaseController {
    private IAuthenticationManager AuthenticationManager {
        get {
            return this.HttpContext.GetOwinContext().Authentication;
        }
    }

    private UserManager<Employee, int> EmployeeManager { get; set; }

    public SiteController(
        UserManager<Employee, int> employeeManager) {
        this.EmployeeManager = employeeManager;
    }

    [HttpGet, AllowAnonymous]
    public ActionResult Default() {
        return base.View();
    }

    [HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
    public async Task<RedirectToRouteResult> Default(
        [Bind(Prefix = "Credentials", Include = "Email,Password")] Credentials credentials) {
        if (this.ModelState.IsValid) {
            Employee employee = await EmployeeManager.FindAsync(credentials.Email, credentials.Password);

            if (employee != null) {
                ClaimsIdentity identityClaim = await this.EmployeeManager.CreateIdentityAsync(employee, DefaultAuthenticationTypes.ApplicationCookie);

                if (identityClaim != null) {
                    AuthenticationManager.SignIn(new AuthenticationProperties(), identityClaim);

                    return base.RedirectToAction("Dashboard");
                }
            }
        }

        return base.RedirectToAction("Default");
    }

    [HttpGet]
    public RedirectToRouteResult SignOut() {
        this.AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

        return base.RedirectToAction("Default");
    }
}

就机器密钥而言,是的,当我将解决方案复制到家用计算机时,确实发生了变化。话虽这么说,我把它从一台Windows 7机器带到另一台Windows 7机器,我从未在任何配置文件中指定机器密钥,因此它在两台机器上的行为应该相同。至于盐,我不认为我在任何地方设置。我只有三四天的ASP.NET身份实现,所以它可能不完整。

1 个答案:

答案 0 :(得分:0)

嗯,事实证明这真的很愚蠢。问题是由于实体框架没有意识到要插入的记录,因为我选择在数据库初始化程序中执行SQL脚本,因为我有很多语句,并且不想写对象初始化等效项。事实证明,即使正确的数据在那里,由于EF没有创建和缓存对象,它只是在整个时间内返回null。它甚至没有尝试去数据库并检查数据是否存在。

所以,经验教训:不要使用ExecuteSqlCommand将数据播种到初始化程序的数据库中。在这上面浪了一整天,我欣喜若狂!