我正在遇到一个我正在研究的解决方案的特殊问题。它使用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身份实现,所以它可能不完整。
答案 0 :(得分:0)
嗯,事实证明这真的很愚蠢。问题是由于实体框架没有意识到要插入的记录,因为我选择在数据库初始化程序中执行SQL脚本,因为我有很多语句,并且不想写对象初始化等效项。事实证明,即使正确的数据在那里,由于EF没有创建和缓存对象,它只是在整个时间内返回null。它甚至没有尝试去数据库并检查数据是否存在。
所以,经验教训:不要使用ExecuteSqlCommand
将数据播种到初始化程序的数据库中。在这上面浪了一整天,我欣喜若狂!