在ASP.NET MVC中实现“记住我”功能

27

我正在尝试为我的登录表单实现“记住我”功能。我使用ASP.NET MVC作为我的Web应用程序。我设法使cookie起作用,但是如果用户在之前勾选了“记住我”复选框,则无法自动登录用户。我知道问题所在,但我不知道如何解决它。

在我的HomeController中,我有以下内容:

private LoginViewModel CheckLoginCookie()
{
    if (!string.IsNullOrEmpty(_appCookies.Email) && !string.IsNullOrEmpty(_appCookies.Password))
    {
        var login = new LoginViewModel
                        {
                            Email = _appCookies.Email,
                            Password = _appCookies.Password
                        };

        return login;
    }
    return null;
}


public ActionResult Index()
{
    var login = CheckLoginCookie();
    if (login != null)
        return RedirectToAction("Login", "User", login);

    var viewModel = new HomeIndexViewModel
                        {
                            IntroText =
                                "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
                            LastMinuteDeals = new List<ItemsIndexViewModel>(),
                            TrustedDeals = new List<ItemsIndexViewModel>()
                        };
    return View(viewModel);
}

在我的UserController中,我有一个名为Login的操作方法:

public ActionResult Login()
{
    return PartialView(new LoginViewModel());
}

[HttpPost]
public ActionResult Login(LoginViewModel dto)
{
    bool flag = false;
    if (ModelState.IsValid)
    {
        if (_userService.AuthenticateUser(dto.Email, dto.Password, false)) {
            var user = _userService.GetUserByEmail(dto.Email);
            var uSession = new UserSession
            {
                ID = user.Id,
                Nickname = user.Nickname
            };
            SessionManager.RegisterSession(SessionKeys.User, uSession);
            flag = true;

            if(dto.RememberMe)
            {
                _appCookies.Email = dto.Email;
                _appCookies.Password = dto.Password;
            }
        }
    }
    if (flag)
        return RedirectToAction("Index", "Home");
    else
    {
        ViewData.Add("InvalidLogin", "The login info you provided were incorrect.");
        return View(dto);
    }
}

基本上,我的想法是,在主页控制器的Index操作结果中检查是否有登录cookie,如果有,则将用户重定向。但问题在于,RedirectToAction将触发GET Login操作方法,而不是负责登录用户的POST方法。

我完全错了吗?或者有没有办法使用RedirectToAction或其他方式调用POST Login方法?

1个回答

61

首先,你不应该将用户凭据存储在cookie中,这是极其不安全的。密码将随每个请求传递,并以明文形式存储在用户的计算机上。

其次,在牵涉到安全性时,不要重新发明轮子,因为你永远无法做到完美。

ASP.Net已经通过Forms Authentication和Membership Providers提供了这种功能的安全实现。你应该看一下它们。创建一个默认的MVC项目将包括基本的身份验证设置。官方MVC网站有更多信息。

更新

你仍然可以在不实现会员提供程序的情况下使用.NET Forms身份验证。在基本级别上,它将按如下方式工作。

你需要在web.config中启用Forms身份验证。

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>

通过在需要安全保护的操作或控制器上添加[Authorize]属性进行装饰。

[Authorize]
public ViewResult Index() {
  //you action logic here
}

然后创建一个基本的登录操作。

[HttpPost]
public ActionResult Login(LoginViewModel dto) {

  //you authorisation logic here
  if (userAutherised) {
    //create the authentication ticket
    var authTicket = new FormsAuthenticationTicket(
      1,
      userId,  //user id
      DateTime.Now,
      DateTime.Now.AddMinutes(20),  // expiry
      rememberMe,  //true to remember
      "", //roles 
      "/"
    );

    //encrypt the ticket and add it to a cookie
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,   FormsAuthentication.Encrypt(authTicket));
    Response.Cookies.Add(cookie);

    return RedirectToAction("Index");

  }

}

3
+1 特别是为了创建一个默认的MVC项目。如果我有任何需要登录功能的项目,我会创建一个新的MVC互联网应用程序,然后从那里更改代码。 - gideon
18
请不要将用户ID存储在Cookie中。用户只需要点击几下即可编辑该Cookie,并以其他用户身份登录。 - Radu094
如果您将身份验证票证的生存期和 cookie 的到期日期设置为未来日期,则用户将一直登录,直到指定日期或注销。这就是用户如何被记住的。 - David Glenn
5
我需要为代码正确运行添加以下内容: if (authTicket.IsPersistent) { cookie.Expires = authTicket.Expiration; } 在将cookie添加到响应之前。 - Arturo Molina
1
有人能告诉我如何在再次打开网站时检查 cookie 吗? - Usman Younas
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接