Вызов PasswordSignIn и SendTwoFactorCode в одном запросе - PullRequest
0 голосов
/ 22 ноября 2018

Я хотел бы реализовать следующий поток для двухфакторной аутентификации в asp.net mvc:

var res = sign.PasswordSignIn("myusername", "mypassword", false, false);
if(res == SignInStatus.RequiresVerification)
   sign.SendTwoFactorCode("EmailCode");

Однако я обнаружил, что функция SendTwoFactorCode возвращает false и не отправляет электронное письмо, потому чтовнутренне он проверяет, проверен ли пользователь. См. Эту строку в источнике. Если я сделаю второй запрос, вызов SendTwoFactorCode будет работать так, как я ожидал.

Есть ли способ заставить SendTwoFactorCode работать правильно сразупосле звонка на PasswordSignIn?

1 Ответ

0 голосов
/ 27 ноября 2018

Есть ли способ заставить корректно работать SendTwoFactorCode сразу после вызова PasswordSignIn?

Краткий ответ: Нет

Предлагаемая альтернатива:

Поток, обычно рекомендуемый в документации:

  1. Аутентификация пользователя через имя пользователя и пароль.
  2. Если действительный пользователь и пароль, и требуется дополнительная проверка, так как 2FA включен, топеренаправить на страницу для отправки кода.
  3. Если пользователь инициирует отправку кода, код отправляется, а затем пользователь перенаправляется на страницу подтверждения.

ВторойШаг обычно заключается в подтверждении поставщика, если есть несколько (например, SMS, электронная почта, и т. д.), чтобы использовать для проверки 2-го фактора.

Например, следующее выполняет перенаправление на RequiresVerification результат

Аккаунт / Логин

//...

var result = await signInManager.PasswordSignInAsync(username, password, false, false);
switch (result) {
    case SignInStatus.Success:
        return RedirectToLocal(returnUrl);
    case SignInStatus.LockedOut:
        return View("Lockout");
    case SignInStatus.RequiresVerification:
        return RedirectToAction("VerifyCode", new { ReturnUrl = returnUrl });
    case SignInStatus.Failure:
    default:
        ModelState.AddModelError("", "Invalid login attempt.");
        return View(model);
}

Но так как вы уже определили, чтоВы собираетесь отправить код по электронной почте, затем вы можете пропустить второй шаг и перенаправить непосредственно на проверочный код, который может быть там, где код отправляется и проверяется.

Account / VerifyCode

[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string returnUrl) {
    var provider = "EmailCode";
    // Require that the user has already logged in via username/password
    var userId = await signInManager.GetVerifiedUserIdAsync();
    if (userId == null) {
        return View("Error");
    }
    // Generate the token and send it
    if(!await signInManager.SendTwoFactorCodeAsync(provider)) {
        return View("Error");
    }

    var model = new VerifyCodeViewModel { 
        ReturnUrl = returnUrl
    };

    return View(model);
}

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyCode(VerifyCodeViewModel model) {
    var provider = "EmailCode";
    if (!ModelState.IsValid) {
        return View(model);
    }

    var result = await signInManager.TwoFactorSignInAsync(provider, model.Code, false, false);
    switch (result) {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("VerifyCode", new { ReturnUrl = returnUrl });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}

Это должно позволить включить TwoFactorCookie в следующий запрос, чтобы GetVerifiedUserIdAsync вел себя как ожидалось.

/// <summary>
/// Get the user id that has been verified already or null.
/// </summary>
/// <returns></returns>
public async Task<TKey> GetVerifiedUserIdAsync()
{
    var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.TwoFactorCookie).WithCurrentCulture();
    if (result != null && result.Identity != null && !String.IsNullOrEmpty(result.Identity.GetUserId()))
    {
        return ConvertIdFromString(result.Identity.GetUserId());
    }
    return default(TKey);
}

Источник

Так же, как вы указали

Если я сделаю второй запрос, вызов SendTwoFactorCode будет работать так, как я ожидаю.

Этот второй запрос важен, так как онбудет включать файл cookie, установленный в предыдущем запросе.

Ссылка Как SignInManager проверяет требование 2FA

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...