阻止未确认电子邮件的用户登录ASP.. Net MVC with Identity 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(),但我不知道为什么它做了这项工作,但它将用户重定向到登录页面returnUrl="帐户/下线"所以在他们确认了他们的电子邮件并试图登录后,他们被注销了,我真的很困惑!!这是我的LogOff()动作方法:

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

我已经谷歌了好几天没有任何运气!!!!

也许有点晚了,但我希望它能帮助别人。

添加

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);

第一个代码块只是检查模型中的电子邮件是否存在于数据库中,并获取它的id来检查它是否未被确认,如果是,则返回一个视图给用户,其中表示已确认,如果已确认,则允许用户登录。

并像这样删除对结果开关的更改

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);
        }

与其移动到另一个页面,为什么不完成这个页面并重定向到正确的操作/视图:

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

您确实需要一个名称为ConfirmEmailAddress的操作(可能还有视图)。

有一个解决方案,它可能不是最好的方法,但它有效。首先让我试着澄清为什么你的方法不起作用。

在其中一条评论中提到,AuthenticationManager使用cookie。为了更新cookie,您需要使用另一个页面将其发送到客户端。这就是为什么TransferRequest不能工作的原因。

如何处理邮件验证?我使用的策略:

1) On SignInStatus。成功,这意味着用户已登录。

2)当电子邮件未被确认时:发送电子邮件到使用的电子邮件地址。这是安全的,因为用户已经登录了。我们只是阻止进一步的访问直到邮件被核实。每次用户试图在没有验证电子邮件的情况下登录时,都会发送一封新的电子邮件(具有相同的链接)。这可以通过跟踪发送的电子邮件数量来限制。

3)我们不能使用LogOff:这是HttpPost,使用ValidateAntiForgeryToken。

4)重定向到显示电子邮件已发送消息的页面(HttpGet,需要授权)。

5)对于其他验证错误,重定向到另一个方法来签出(HttpGet,需要授权)。不需要视图,重定向到登录页面。

In code:更新AccountController中的代码。登录:

        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视图。这可能不是一个真正的问题,但它表明我们没有阻止用户登录,只是通过自动注销用户来拒绝登录后的进一步访问。

===更新====

请注意必须正确处理异常。在此场景中,用户被授予访问权限,然后被撤销访问权限。但是,如果在注销之前发生异常并且未捕获此异常,则用户保持登录状态。

当邮件服务器不可用或凭据为空或无效时,可能会发生异常。

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

我会让管理员创建没有任何密码的用户。带链接的邮件应该发给用户。然后用户被引导到SetPassword页面设置新密码。这样,没有人可以访问用户帐户,除非他确认并设置了密码。

不带密码调用CreateAsync

var adminresult = await UserManager.CreateAsync(user);

将admin重定向到新的自定义视图,例如"电子邮件发送给用户"

@{
    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>

如果邮件在数据存储中根本不存在,则@INFINITY_18的答案可能导致Object reference not set to an instance of an object错误。在这种情况下,为什么不返回带有模型错误的Login视图呢?

我建议如下:

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

要求电子邮件确认

最好的做法是确认新用户注册的电子邮件,以验证他们没有冒充别人(也就是说,他们没有注册别人的电子邮件)。假设你有一个讨论论坛,你想防止"yli@example.com"从注册"nolivetto@contoso.com."没有电子邮件确认,"nolivetto@contoso.com"可能会从你的应用程序收到不需要的电子邮件。假设用户不小心注册为"ylo@example.com"也没有注意到"yli "他们将无法使用密码恢复,因为应用程序没有他们正确的电子邮件。电子邮件确认只提供有限的保护,以防止机器人,并不能提供保护,从确定的垃圾邮件发送者谁有许多工作的电子邮件别名,他们可以使用注册。

您通常希望在新用户收到确认电子邮件之前阻止他们向您的网站发布任何数据。

更新ConfigureServices以要求确认电子邮件:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>(config =>
        {
            config.SignIn.RequireConfirmedEmail = true;
        })
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();
    // Add application services.
    services.AddTransient<IEmailSender, EmailSender>();
    services.AddMvc();
    services.Configure<AuthMessageSenderOptions>(Configuration);
}

相关内容

  • 没有找到相关文章

最新更新