Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net core Identity, getting meaningful login failed reason

When a login fails, I wish to know if it was the username, the password or something else.

var signinResult = await _signInManager.PasswordSignInAsync(
    loginViewModel.UserName,
    loginViewModel.Password,
    false, false);

returns SignInResult which just tells me that it's NotAllowed.

Can I get a more meaningful reason from Identity somehow?

like image 283
user2328625 Avatar asked Nov 30 '22 14:11

user2328625


2 Answers

NotAllowed means either the Email or Phone Number have't been confirmed (and confirmation is required). You can check this explicitly with something like the following (assuming you have a UserManager instance from DI):

await _userManager.IsEmailConfirmedAsync(user);
await _userManager.IsPhoneNumberConfirmedAsync(user);

To use either of those two functions, you'll need the user:

var user = await _userManager.FindByNameAsync(loginViewModel.UserName);

To determine whether it was the username or the password that failed, you'll need to first check IsLockedOut, IsNotAllowed and RequiresTwoFactor. If all of these return false, the username or password is incorrect. In order to determine which of these is the problem, you can check the return value from await _userManager.FindByNameAsync(user). Here's a complete example:

var signinResult = await _signInManager.PasswordSignInAsync(
    loginViewModel.UserName, loginViewModel.Password, false, false);

var user = await _userManager.FindByNameAsync(loginViewModel.UserName);

if (signinResult.IsNotAllowed)
{
    if (!await _userManager.IsEmailConfirmedAsync(user))
    {
        // Email isn't confirmed.
    }

    if (!await _userManager.IsPhoneNumberConfirmedAsync(user))
    {
        // Phone Number isn't confirmed.
    }
}
else if (signinResult.IsLockedOut)
{
    // Account is locked out.
}
else if (signinResult.RequiresTwoFactor)
{
    // 2FA required.
}
else
{
    // Username or password is incorrect.
    if (user == null)
    {
        // Username is incorrect.
    }
    else
    {
        // Password is incorrect.
    }
}
like image 55
Kirk Larkin Avatar answered Dec 06 '22 12:12

Kirk Larkin


PasswordSignInAsync returns only a generic failure if the username/password is incorrect. This is because you really shouldn't be exposing which is wrong in the first place. If you explicitly tell the end-user that the password is wrong, then they now know that the username is good. If this is a malicious user, you've halved their work. Now they can just brute-force the password.

If you do want this information, though, simply attempt to get the user by the username first:

var user = await _userManager.FindByNameAsync(loginViewModel.UserName);
if (user == null)
{
    // username is invalid
}

// Now attempt to login with password.
like image 38
Chris Pratt Avatar answered Dec 06 '22 13:12

Chris Pratt