Подтвердить что ты не робот

Запретить пользователям без подтвержденной электронной почты регистрироваться в ASP.Net MVC с идентификатором 2

В microsoft Identity 2 есть возможность, чтобы пользователи могли подтвердить наличие адресов электронной почты, которые я загрузил в проект Identity 2 из здесь, в этом проекте нет никакой разницы между пользователями подтвердили свои электронные письма и кто не хочет, чтобы люди не подтвердили, что их электронные письма не могут войти в систему, это то, что я пробовал:

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }


        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
        switch (result)
        {
            case SignInStatus.Success:
                {


                    var user = await UserManager.FindByNameAsync(model.Email);
                    if (user != null)
                    {
                        if (!await UserManager.IsEmailConfirmedAsync(user.Id))
                        {
                            //first I tried this.
                            //return LogOff();
                            HttpContext.Server.TransferRequest("~/Account/LogOff");
                            return RedirectToAction("Login");
                        }
                    }

                    return RedirectToLocal(returnUrl);
                }
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);

Я попытался заставить пользователя выйти из системы, вызвав метод действия LogOff(), но он не работает, и пользователь остается аутентифицированным. Затем я попытался использовать Server.TransferRequest(), но я не знаю, почему он выполнял эту работу, но перенаправляет пользователей к странице входа с возвратомUrl = "Учетная запись/Выход" поэтому после того, как они подтвердили свою электронную почту и попытались войти в систему, они получили выход из системы, и я действительно запутался!! это мой метод действия LogOff():

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut();
        return RedirectToAction("About", "Home");
    }

Я искал его в течение нескольких дней без везения!!!!

4b9b3361

Ответ 1

Может быть, это немного поздно, но я надеюсь, что это может помочь другим.

Добавьте это

var userid = UserManager.FindByEmail(model.Email).Id;
        if (!UserManager.IsEmailConfirmed(userid))
        {
            return View("EmailNotConfirmed");
        }

перед

var result = await SignInManager.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 });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }

Ответ 2

Вместо того, чтобы переходить на другую страницу, почему бы не закончить этот и не перенаправить правильное действие/представление:

if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
    return RedirectToAction("ConfirmEmailAddress", new { ReturnUrl = returnUrl });
}

Вам нужно действие (и, возможно, представление) с именем ConfirmEmailAddress, хотя.

Ответ 3

Существует решение, которое, возможно, не лучший подход, но оно работает. Сначала позвольте мне попытаться выяснить, почему ваш подход не сработал.

В одном из комментариев, о котором говорится, AuthenticationManager использует cookies. Чтобы обновить файл cookie, вам необходимо отправить его клиенту, используя другую страницу. Вот почему TransferRequest не будет работать.

Как обрабатывать электронную почту? Стратегия, которую я использовал:

1) В SignInStatus.Success это означает, что пользователь вошел в систему.

2) Когда электронная почта не подтверждена: отправьте электронное письмо на использованный адрес электронной почты. Это безопасно, поскольку пользователь уже выполнил вход. Мы просто блокируем дальнейший доступ до тех пор, пока не будет проверена электронная почта. Каждый раз, когда пользователь пытается войти в систему без проверки подлинности электронной почты, отправляется новое электронное письмо (с той же ссылкой). Это может быть ограничено путем отслеживания количества отправленных писем.

3) Мы не можем использовать LogOff: это HttpPost и использует ValidateAntiForgeryToken.

4) Перенаправление на страницу (требуется HttpGet, требуется авторизация), на котором отображается сообщение о том, что отправлено электронное письмо. При входе выведите пользователя.

5) Для других ошибок проверки перенаправляйтесь к другому методу выхода (HttpGet, требуется авторизация). Не требуется просмотр, перенаправление на страницу входа.

В коде: обновите код в AccountController.Login:

        case SignInStatus.Success:
        {
            var currentUser = UserManager.FindByNameAsync(model.Email);
            if (!await UserManager.IsEmailConfirmedAsync(currentUser.Id))
            {
                // Send email
                var code = await UserManager.GenerateEmailConfirmationTokenAsync(currentUser.Id);
                var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = currentUser.Id, code = code}, protocol: Request.Url.Scheme);
                await UserManager.SendEmailAsync(currentUser.Id, "Confirm your account", string.Format("Please confirm your account by clicking this link: <a href=\"{0}\">link</a>", callbackUrl));
                // Show message
                return RedirectToAction("DisplayEmail");
            }
            // Some validation
            if (true)
            {
                return RedirectToAction("SilentLogOff");
            }
            return RedirectToLocal(returnUrl);
        }

Добавить методы AccountController:

// GET: /Account/SilentLogOff
[HttpGet]
[Authorize]
public ActionResult SilentLogOff()
{
    // Sign out and redirect to Login
    AuthenticationManager.SignOut();
    return RedirectToAction("Login");
}

// GET: /Account/DisplayEmail
[HttpGet]
[Authorize]
public ActionResult DisplayEmail()
{
    // Sign out and show DisplayEmail view
    AuthenticationManager.SignOut();
    return View();
}

DisplayEmail.cshtml

@{
    ViewBag.Title = "Verify e-mail";
}

<h2>@ViewBag.Title.</h2>
<p class="text-info">
    Please check your email and confirm your email address.
</p>

Вы заметите, что пользователь не может связаться с другими страницами, пока не будет проверена электронная почта. И мы можем использовать функции SignInManager.

С этим подходом существует одна возможная проблема (я могу придумать), пользователь регистрируется на время отправки сообщения электронной почты и перенаправляется на просмотр DisplayMessage. Это может не быть реальной проблемой, но это показывает, что мы не запрещаем пользователю входить в систему, а только отказываемся от дальнейшего доступа после входа в систему, автоматически выгружая пользователя.

=== Обновление ====

Обратите внимание, что исключения должны обрабатываться надлежащим образом. Пользователю предоставляется доступ, а затем в этом сценарии аннулируется доступ. Но в случае возникновения исключения перед выпиской, и это исключение не было обнаружено, пользователь остается в системе.

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

===============

Ответ 4

Я бы позволил администратору создать пользователя без пароля. Электронная почта со ссылкой должна перейти к пользователю. Затем пользователь перенаправляется на страницу SetPassword для установки нового пароля. Таким образом, никто не может получить доступ к учетной записи пользователя, если он не подтвердит и не установит пароль.

Вызов CreateAsync без пароля

var adminresult = await UserManager.CreateAsync(user);

Перенаправить администратора в новый пользовательский вид, говорящий что-то вроде "Электронная почта отправляется пользователю"

@{
    ViewBag.Title = "New User created and Email is Sent";
}
<h2>@ViewBag.Title.</h2>
<p class="text-info">
    The New User has to follow the instructions to complete the user creation process.
</p>
<p class="text-danger">

    Please change this code to register an email service in IdentityConfig to send an email.
</p>

Ответ 5

Ответ @INFINITY_18 может вызвать ошибку Object reference not set to an instance of an object, если письмо вообще не существует в хранилище данных. И почему бы не вернуть вид входа в систему с ошибкой модели в этом случае?

Я бы предложил следующее:

var userid = UserManager.FindByEmail(model.Email)?.Id;
if (string.IsNullOrEmpty(userid) || !UserManager.IsEmailConfirmed(userid)))
{
    ModelState.AddModelError("", "Invalid login attempt.");
    return View(model);
}