简体   繁体   中英

Microsoft Identity 2 SignInManager never returns VerificationRequired

I'm trying to add 2-factor authentication using pin codes sent in email. The 2FA step is only required by users 30 days after they last completed the 2FA step.

Project's tech is ASP.NET MVC 5 using EntityFramework 6 with NuGet package version 2.2.2 of the Microsoft.AspNet.Identity packages(.Core, .EntityFramework, .Owin).

I've been following the advice in this tutorial, but integrating it in my company's already existing solution: https://docs.microsoft.com/en-us/aspnet/identity/overview/features-api/two-factor-authentication-using-sms-and-email-with-aspnet-identity

My problems

SignInManager never returns RequiresVerification when using the PasswordSignIn I assumed that I should expect this login status, when the "TwoFactorEnabled" flag is set to true in the database for each user. I'm not sure if I should use this, if I only want users to go through the 2FA verification every 2 weeks, as it's my impression that it will require users to go through this every time. Either that, or I should use a timestamp set on the user to determine, if it's time to reenable the "TwoFactorEnabled" flag?

I can't retrieve the verified user's ID, when verifying code I thought that after performing a normal PasswordSignIn, the server would be able to retrieve the user's ID, for example when verifying that the entered pin code is correct:

[HttpPost]
    [AllowAnonymous]
    public async Task<ActionResult> VerifyCode(string pin)
    {
        string userId = await SignInManager.GetVerifiedUserIdAsync().WithCurrentCulture();

        if (userId == null || String.IsNullOrEmpty(pin))
        {
            return View("Error");
        }

        var user = await UserManager.FindByIdAsync(userId);

        if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, "EmailCode", pin))
        {
            await SignInManager.SignInAsync(user, false, false);
            return RedirectToAction("Index", "Dashboards");
        }
        else
        {
            ModelState.AddModelError("", "Invalid code");
        }

        return View();
    }

It's a little bit confusing, since most tutorials are very old, and use the AuthenticationManager, which I have never seen before.

How do I prevent users from simply skipping to other pages from the verification screen, if they're already "successfully logged in with username and password" Won't they be able to bypass the Authorization attribute at this point?

What already works I can get the UserManager to send an email with a token(pin code), and it will be successfully verified, if I enter the correct user ID

What I have done I have the standard/default Identity setup, so we're using the standard configuration pretty much that comes with new MVC 5 projects.

Startup.Auth:

// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(10));

        // Enables the application to remember the second login verification factor such as phone or email.
        // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
        // This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

2FA provider setup in ApplicationUserManager:

        manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });

        manager.EmailService = new EmailService();
        //manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }

        return manager;

Thank you very much in advance for any help.

I think I may have figured out what the problem is. The UserManager returned 0 for GetValidTwoFactorProvidersAsync. It seems that this occurs, when the email isn't confirmed for the user. I tried settings email as confirmed for the user, and now RequiresVerification is returned.

When RequiresVerification is returned, it seems the user isn't completely signed in, but I'm still able to fetch the user ID in subsequent code verification calls using the SignInManager's GetVerifiedUserId method.

So now, when a user logs in, before performing the password sign-in, I simply perform a check to see, when the user last completed 2FA authentication. If it's been more than 30 days, I reenable the 2FA flag in the database. Then when the password signin is performed, I'll get RequiresVerification as expected, and I can continue the rest of the flow as any standard 2FA verification would otherwise require.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM