Двухэтапная аутентификация в ASP.Net MVC - PullRequest
6 голосов
/ 24 мая 2011

Я работаю над приложением ASP.Net Mvc 3, используя FormsAuthentication с пользовательским MembershipProvider (поэтому у меня есть некоторый контроль над тем, что возвращает провайдер).

Требования требуют 2-пошаговый процесс аутентификации (имя пользователя и пароль, за которым следует секретный вопрос).Пользователь не должен иметь доступ к любому из «безопасных» разделов сайта, не пройдя оба шага.Пожалуйста, не упоминайте, является ли это многофакторной безопасностью или нет, я уже знаю.

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

Вот некоторые соображения:

  • Мне разрешено (архитектурно) использовать сеанс - я бы предпочел не делать этого.
  • Я бы предпочел использовать готовый комплект [Authorize] ActionFilter для контроллеров, предоставляющих защищенный контент.
  • Ответственные лица хотели бы, чтобы URL для двух шагов был одинаковым: то есть www.contoso.com/login/.По крайней мере, в моих попытках это вызвало некоторые незначительные, но не незначительные проблемы, когда пользователи вводят неправильный ответ на втором шаге (они официально не вошли в систему, но я должен убедиться, что я все еще работаю против половинысекретный вопрос / ответ аутентифицированного пользователя).

Спасибо.

Ответы [ 2 ]

4 голосов
/ 24 мая 2011

Использование пользовательской модели представления в сочетании со скрытыми полями формы. Просто убедитесь, что все сделано по https.

ViewModel

public LoginForm
{
    public string UserName { get; set; }
    public string Password { get; set; }

    public int SecretQuestionId { get; set; }
    public string SecretQuestion { get; set; }
    public string SecretQuestionAnswer { get; set; }
}

Методы действий

public ActionResult Login()
{
    var form = new LoginForm();
    return View(form);
}

[HttpPost]
public ActionResult Login(LoginForm form)
{
    if (form.SecretQuestionId == 0)
    {
        //This means that they've posted the first half - Username and Password
        var user = AccountRepository.GetUser(form.UserName, form.Password);
        if (user != null)
        {
            //Get a new secret question
            var secretQuestion = AccountRepository.GetRandomSecretQuestion(user.Id);
            form.SecretQuestionId = secretQuestion.Id;
            form.SecretQuestion = secretQuestion.QuestionText;
        }
    }
    else
    {
        //This means that they've posted from the second half - Secret Question
        //Re-authenticate with the hidden field values
        var user = AccountRepository.GetUser(form.UserName, form.Password);
        if (user != null)
        {
            if (AccountService.CheckSecretQuestion(form.SecretQuestionId, form.SecretQuestionAnswer))
            {
                //This means they should be authenticated and logged in
                //Do a redirect here (after logging them in)
            }
        }
    }

    return View(form);
} 

View

<form>
    @if (Model.SecretQuestionId == 0) {
        //Display input for @Model.UserName
        //Display input for @Model.Password
    }
    else {
        //Display hidden input for @Model.UserName
        //Display hidden input for @Model.Password
        //Display hidden input for @Model.SecretQuestionId
        //Display @Model.SecretQuestion as text
        //Display input for @Model.SecretQuestionAnswer
    }
</form>

Если вы недовольны отправкой имени пользователя и пароля обратно в представление в скрытых полях для повторной аутентификации и убедитесь, что они не обманывают ... вы можете создать HMAC или что-то подобное для проверки. 1018 *

Кстати, этот вопрос выглядит как несколько вопросов, объединенных в один ... поэтому просто ответили, как выполнить двухэтапную аутентификацию с помощью одного метода представления / действия.

0 голосов
/ 24 мая 2011

Я бы, вероятно, сделал что-то, где первый шаг заставил бы их ввести имя пользователя и пароль.Отметьте, если это хорошо, переместите их к разрешенному представлению, которое попросит их ввести ответ на вопрос.Если они потерпят неудачу, запишите их, загрузите их, что угодно.Я не думаю, что это возможно в одном представлении, если вы не отредактируете частичное представление, и если они уйдут без завершения процесса аутентификации, вы выйдете из них и очистите их cookie.

---- EDIT----- Если подумать, вы можете сделать частичное представление, просто не регистрируйте их, пока они не завершат вторую часть частичного представления.Какой-то псевдо-код:

public ActionResult Login(){
  get username and password off the view
  if its valid
     render a partial view that asks for the secret answer
     if thats valid
       forms auth login
     else
       try again, get booted, or whatever
   else
      get booted, try again, whatever
}
...