首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“忘记密码”功能

“忘记密码”功能
EN

Code Review用户
提问于 2017-04-23 04:17:45
回答 2查看 6.8K关注 0票数 6

我想在Asp.Net MVC 5中实现“忘记密码”功能。

  1. 获取用户电子邮件ID
  2. 让用户在他的电子邮件收件箱中输入收到的令牌。
  3. 如果令牌匹配,则重定向密码重置页。
  4. 设置新密码

请告诉我哪里可以改进。

代码语言:javascript
复制
public ActionResult ForgotPassword()
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ForgotPassword(ForgotPasswordMV viewModel)
{
    if (ModelState.IsValid)
    {
        if (SecurityHelper.SendEmail(viewModel.Email))
            return RedirectToAction("VerifyToken", new { email = viewModel.Email });
        ModelState.AddModelError("Email", "Email not found");
    }

    return View();
}

public ActionResult VerifyToken(string email = null)
{
    VerifyTokenMV viewModel = new VerifyTokenMV
    {
        Email = email,
        Token = ""
    };

    return View(viewModel);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult VerifyToken(VerifyTokenMV viewModel)
{
    if (ModelState.IsValid)
    {
        if (SecurityHelper.VerifyToken(viewModel.Token, viewModel.Email))
            return RedirectToAction("ConfirmPassword", new { email = viewModel.Email });
        ModelState.AddModelError("Token", "Token does not match");

    }

    return View();
}

public ActionResult ConfirmPassword(string email = null)
{
    ConfirmPasswordMV viewModel = new ConfirmPasswordMV
    {
        EmailID = email
    };
    return View(viewModel);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ConfirmPassword(ConfirmPasswordMV viewModel)
{
    if (ModelState.IsValid)
    {
        if (viewModel.Password == viewModel.ConfirmPassword)
        {
            SecurityHelper.UpdatePassword(viewModel.EmailID, viewModel.Password);
            TempData["Message"] = "Your password has been updated.";
            return RedirectToAction(action, homeController);
        }
        ModelState.AddModelError("", "Password does not match.");
    }

    return View();
}

视图模型

代码语言:javascript
复制
public class ConfirmPasswordMV
{
    [Display(Name = "Enter your new password"), Required]
    public string Password { get; set; }

    [Display(Name = "Confirm Password"), Required]
    public string ConfirmPassword { get; set; }

    public string EmailID { get; set; }
}

public class VerifyTokenMV
{
    [Display(Name = "Enter Verification Token sent to your email"), Required]
    public string Token { get; set; }

    public string Email { get; set; }
}

    public class ForgotPasswordMV
{
    [Display(Name = "Enter your email:"), Required]
    public string Email { get; set; }
}

视图

代码语言:javascript
复制
@using (@Html.BeginForm("VerifyToken", "Security"))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(m => m.Email)
    @Html.ValidationSummary(true, "Please fix below errors")
    <div class="form-group">
        @Html.LabelFor(m => m.Token)
        @Html.TextBoxFor(m => m.Token, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Token)
    </div>
    <button class="btn btn-primary">Continue</button>
}

视图2

代码语言:javascript
复制
@using (@Html.BeginForm("ConfirmPassword", "Security"))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(m => m.EmailID)
    @Html.ValidationSummary(true, "Please fix below errors")
    <div class="form-group">
        @Html.LabelFor(m => m.Password)
        @Html.TextBoxFor(m => m.Password, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Password)
     </div>
    <div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword)
        @Html.TextBoxFor(m => m.ConfirmPassword, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.ConfirmPassword)
    </div>
    <button class="btn btn-primary">Save Password</button>
}

视图3

代码语言:javascript
复制
<p>@ViewBag.ErrorMessage</p>

@using (@Html.BeginForm("ForgotPassword", "Security"))
{
    @Html.ValidationSummary(true, "Please fix below error")
    @Html.AntiForgeryToken()
    <div class="form-group">
        @Html.LabelFor(m => m.Email)
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Email)
    </div>
    <button class="btn btn-primary">Continue</button>
}

Note

  1. 请注意,我正在将电子邮件作为隐藏字段传递给每个屏幕,因此在控制器中也是如此,这样我就可以验证正确的用户。我使用了一个匿名对象。这是我的新手尝试,所以请告诉我,我可以做的缺点/改进。
  2. 我是否可以有一个观点,并将所有这些作为部分观点?
  3. 对于这些页面,我真的需要三个单独的视图模型吗?
  4. 作为用VB.NET代码编写的代码hits API,我没有直接与模型进行交互。

编辑

  1. 在DB a. token b. emailId c. TimeStamp中有三列
  2. 如果时间超过5分钟,我就过期。
EN

回答 2

Code Review用户

回答已采纳

发布于 2017-04-24 09:38:41

这是安全的吗?

不是的。这是不安全的,因为你可以改变任何人的电子邮件地址在最后一步。要做到这一点,我所需要做的就是更改存储在隐藏字段中的emailId (例如,使用我的浏览器工具)。

在最后一步中,您必须验证令牌。你根本不需要第二步。

一旦获得重置令牌,就需要两个请求。通常情况下,您会单击电子邮件中的链接。

获取passwordReset (通过重置令牌)

POST passwordReset (通过重置令牌和新密码)

使用重置令牌查找您要更改密码的电子邮件。标记应该是有时间限制的、长的和随机的,以避免猜测。

票数 3
EN

Code Review用户

发布于 2017-04-26 18:28:17

我有几个建议。

首先,您在控制器中遇到了一些代码重复,需要对模型状态进行重复检查,看看Jimmy的帖子,看看解决这个问题的一种方法。您不必完全遵循他的建议,以下是我在一些项目中使用的变体。

代码语言:javascript
复制
public abstract class DefaultController : Controller
  {
    internal IActionResult Form<TForm>(TForm form, IFormResultRequest<TForm> request, Func<IActionResult> success, Func<IActionResult> failure)
    {
      if (!ModelState.IsValid)
        return failure();
      var formResult = request.Handle(form);
      if (!formResult.Success)
      {
        ModelState.AddModelError("error", formResult.ErrorMessage);
        failure();
      }
      return success();
    }

然后让您的控制器继承此默认控制器,并执行如下操作:

代码语言:javascript
复制
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Validate(ValidateEditModel form, IFormResultRequest<ValidateEditModel> request)
{
  return Form(form, request,
    success: () => RedirectToAction(...),
    failure: () => View(form as ValidateViewModel));
}

此操作方法从DI容器中注入IFormResultRequest<ValidateEditModel>。如果不想使用依赖项注入,则仍然应该使用某种类型的控制器基类来减少重复的模型验证检查。

第二,这个控制器非常“肥胖”,这意味着它包含了太多的代码,从而导致它不能很好地扩展,并且使它更难阅读。难以阅读的代码很难调试。另外,您正在验证令牌并在控制器中更改密码,这是业务逻辑,而业务逻辑不应该包含在控制器中。我建议使用某种类型的软件设计模式来分离这个逻辑(例如:依赖注入的CQRS )。

这些建议只适用于后端代码,并取决于应用程序的规模。如果您的应用程序足够小,那么使用依赖注入的CQRS很可能并不理想,因为它所提供的回报将不值得付出努力。无论哪种方式,您的业务逻辑都需要包含在它自己的层中。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/161566

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档