I have implemented a custom UserStore
, it implements IUserStore<DatabaseLogin, int>
and IUserPasswordStore<DatabaseLogin, int>
.
My Login action method is as below:
if (ModelState.IsValid)
{
if (Authentication.Login(user.Username, user.Password))
{
DatabaseLogin x = await UserManager.FindAsync(user.Username, user.Password);
DatabaseLogin Login = Authentication.FindByName(user.Username);
if (Login != null)
{
ClaimsIdentity ident = await UserManager.CreateIdentityAsync(Login,
DefaultAuthenticationTypes.ApplicationCookie);
AuthManager.SignOut();
AuthManager.SignIn(new AuthenticationProperties
{
IsPersistent = false
}, ident);
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid Login");
}
}
return View();
In the custom authentication class that I wrote, Authentication
, I have a Login method that works fine, also FindByName
method returns an app user. But if I try to SignIn
with that login, the user isn't recognized as authenticated and HttpContext.User.Identity
is always null, so I imagine that I have to try UserManager.FindAsync
.
This method calls FindByNameAsync
and GetPasswordHashAsync
, and it always return null.
public Task<DatabaseLogin> FindByNameAsync(string userName)
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("userName");
return Task.FromResult<DatabaseLogin>(Authentication.FindByName(userName));
}
public Task<string> GetPasswordHashAsync(DatabaseLogin user)
{
if (user == null)
throw new ArgumentNullException("user");
return Task.FromResult<string>(user.Password);
}
And the Authentication.FindByName
public static DatabaseLogin FindByName(string name)
{
string GetUserQuery = string.Format(
"USE db;SELECT principal_id AS id, name as userName, create_date AS CreateDate, modify_date AS modifyDate FROM sys.database_principals WHERE type='S' AND authentication_type = 1 AND name = '{0}'"
, name);
DatabaseLogin user;
using (var db = new EFDbContext())
{
user = db.Database.SqlQuery<DatabaseLogin>(GetUserQuery).FirstOrDefault();
}
user.Password = Convert.ToBase64String(Encoding.ASCII.GetBytes("pass"));
return user;
}
As you can see I'm using database users, I'm not sure how I can retrieve a hashed password for them. For now, I'm just storing the Base65 of the correct password!
I have no idea where I'm going wrong, any guidance is welcome.
Short answer: nothing's wrong. User is authenticated in other action methods, but apparently not in the current action method.
This is the process that I followed, maybe it will help you debug your app.
After reading the source code, FindAsync
first calls FindByNameAsync
, followed by CheckPasswordAsync
which references VerifyPasswordAsync
. So it should be fine If I could override VerifyPasswordAsync
.
I created a custom password hasher
that implements IPasswordHasher
, and registered it in the create
method of my UserManager
like this:
manager.PasswordHasher = new DbPasswordHasher();
So by now, I can get my user from UserManager.FindAsync
, but it turned out that it doesn't matter where you get the user since HttpContext.User.Identity
is still null! My mistake was that I didn't notice the user isn't authenticated in the current action, in other action methods it works as expected!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With