I'm working with an empty/new MVC5 web project with Identity turned on. I've customized the IdentityModel.cs to use our tables/schema to get user logins.
I can login and get the SignInStatus.Success
, but then when the page loads the _LoginPartial.cshtml
file, it's acting like Request.IsAuthenticated == false
. Is there something I missed when overriding?
My AccountController.cs method looks like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await CustomSignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
Here are the supporting custom classes:
public class CustomSignInManager : SignInManager<CustomUser, string>
{
public CustomSignInManager(CustomUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public static CustomSignInManager Create(IdentityFactoryOptions<CustomSignInManager> options, IOwinContext context)
{
return new CustomSignInManager(context.GetUserManager<CustomUserManager>(), context.Authentication);
}
public override async Task<SignInStatus> PasswordSignInAsync(
string userName,
string password,
bool isPersistent,
bool shouldLockout)
{
if (UserManager == null)
{
return SignInStatus.Failure;
}
var user = await UserManager.FindByNameAsync(userName).WithCurrentCulture();
if (user == null)
{
return SignInStatus.Failure;
}
if (UserManager.SupportsUserPassword
&& await UserManager.CheckPasswordAsync(user, password)
.WithCurrentCulture())
{
return SignInStatus.Success;
}
if (shouldLockout && UserManager.SupportsUserLockout)
{
// If lockout is requested, increment access failed count
// which might lock out the user
await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture();
if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
{
return SignInStatus.LockedOut;
}
}
return SignInStatus.Failure;
}
}
My CustomUserManager:
public class CustomUserManager : UserManager<CustomUser>
{
public CustomUserManager(IUserStore<CustomUser> store)
: base(store)
{
this.PasswordHasher = new SQLPasswordHasher();
}
public static CustomUserManager Create()
{
var manager = new CustomUserManager(new CustomUserStore());
return manager;
}
public override bool SupportsUserLockout {
get { return false; }
}
public override bool SupportsUserPassword
{
get { return true; }
}
// CheckPasswordAsync
public override Task<bool> CheckPasswordAsync(CustomUser user, string password)
{
return Task.Run(() => MyCheckPasswordAsync( user, password));
}
private bool MyCheckPasswordAsync(CustomUser user, string password)
{
using (var db = new MkpContext())
{
var profile = (
from pi in db.ProfileIdentifier
join p in db.Profile on pi.ProfileId equals p.ProfileId
where
pi.ProfileIdentifierTypeId == (int) ProfileIdentifierTypes.email &&
pi.ProfileIdentifierValue == user.UserName &&
pi.IsActive
select p).FirstOrDefault(); // Use email to find profileId
if (profile == null || profile.ProfileId == Guid.Empty) return false;
// Verify password
var verPassResults = PasswordHasher.VerifyHashedPassword(profile.Password + "|" + profile.PasswordSalt,
password);
// Check if valid password
if (verPassResults == PasswordVerificationResult.Failed || password == string.Empty) return false;
}
return true;
}
}
Because you simply don't sign in the user at all! You just check if the user can sign in then return success result instead of actual sign in. Simply alter your PasswordSignInAsync()
method like this:
public override async Task<SignInStatus> PasswordSignInAsync(
string userName,
string password,
bool isPersistent,
bool shouldLockout)
{
// other parts
if (UserManager.SupportsUserPassword
&& await UserManager.CheckPasswordAsync(user, password)
.WithCurrentCulture())
{
// this method actually do the job
return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
}
// rest of code
}