如何正确实现记住我功能? Asp.Net 核心

问题描述 投票:0回答:3

我已经尝试了 2 天来了解如何构建记住我的功能,但没有什么明确的。
首先也是最重要的,我想确保我们同意以下正确的工作流程。

我需要在这里允许用户打开他们的个人资料,而无需 只要用户不注销,即可再次登录 1 个月。

  1. 我使用基于 cookie 的身份验证来存储一些数据,每次打开用户配置文件时我都可以检查这些数据,以确保用户已通过身份验证。
    -- 这一步没有问题

  2. 我在此步骤中使用简单的代码从 cookie 中再次检索数据。
    ——问题来了。只要我登录,我就可以从 cookie 中检索数据,否则,当我停止并重新运行应用程序并直接重定向到用户配置文件而无需再次登录时,我无法读取 cookie 数据,尽管它仍然存在! !

现在让我们看一下代码

启动文件Cookie设置

 public void ConfigureServices(IServiceCollection services){
 .....
 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
 .AddCookie(options => {
     options.Cookie.Name = "RememberMecookie"; // cookie name
     options.LoginPath = "/Account/LogIn"; // view where the cookie will be issued for the first time
     options.ExpireTimeSpan = TimeSpan.FromDays(30); // time for the cookei to last in the browser
     options.SlidingExpiration = true; // the cookie would be re-issued on any request half way through the ExpireTimeSpan
     options.EventsType = typeof(CookieAuthEvent);
 });
 .....
 }

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
 .....
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseCookiePolicy();
    app.UseEndpoints(endpoints =>
    {
      endpoints.MapDefaultControllerRoute();
    }
  .....

  public class CookieAuthEvent : CookieAuthenticationEvents
  {
      public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
      {
          context.Request.HttpContext.Items.Add("ExpiresUTC", context.Properties.ExpiresUtc);
      }
  }

  }

登录视图模型

public class VMLogin
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public bool RememberMe { get; set; }
}

控制器/登录

    [HttpPost]
    public async Task<IActionResult> LoginAsync(VMLogin CurrentUserLog, string returnUrl)
    {
        if (!string.IsNullOrEmpty(CurrentUserLog.UserName) && string.IsNullOrEmpty(CurrentUserLog.Password))
        {
            return RedirectToAction("Login");
        }

        if (ModelState.IsValid)
        {
            var SignInStatus = await signInManager.PasswordSignInAsync
                (CurrentUserLog.UserName, CurrentUserLog.Password, CurrentUserLog.RememberMe, false);
            AppUser _user = await userManager.FindByNameAsync(CurrentUserLog.UserName);
            if (SignInStatus.Succeeded)
            {
                if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)) // to prevent login from outside link
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Name, CurrentUserLog.UserName),
                        new Claim(ClaimTypes.Email, _user.Email),
                        new Claim(ClaimTypes.NameIdentifier, _user.Id.ToString())
                    };
                    
                    var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                    var principal = new ClaimsPrincipal(identity);
                    var props = new AuthenticationProperties{ 
                        IsPersistent = true,
                        ExpiresUtc = DateTime.UtcNow.AddMonths(1)
                    };
                    
                    // to register the cookie to the browser
                    HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, props).Wait();

                    return RedirectToAction("UserProfile");
                }
            }

            ModelState.AddModelError(string.Empty, "Invalid Login Attempt");
        }
        return View(CurrentUserLog);
    }

这就是所有问题。当我第一次登录并首次创建 cookie 时,我从 cookie 中获取数据,如下所示 上面的代码。但是,我无法从同一天获得相同的日期 当我停止调试并再次运行应用程序并重定向到 无需登录即可直接获取 UserProfile,尽管 cookie “RememberMecookie” 仍然存在。

控制器/用户配置文件

    [Authorize]
    public async Task<IActionResult> UserProfile()
    {
        // all lines of code below are working just with the first creation of the cookie with the first login. but if rerun the app again, they all return null if redirect here directly without logIn.

        string userId = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;

        Claim v = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);

        AppUser _user = await userManager.GetUserAsync(HttpContext.User);

        string cookieValueFromReq = Request.Cookies["RememberMecookie"];

        // this is for normal login without remember me functionality
        //AppUser user = await userManager.GetUserAsync(User);
        return View(/*user*/);
    }
asp.net-mvc asp.net-core asp.net-identity asp.net-authentication
3个回答
1
投票

感谢所有花时间检查我的问题的人。我终于找到了问题所在。这段代码真的很棒,它可以作为使用基于 cookie 的身份验证的“记住我”功能的一个很好的参考。而且代码本身没有问题。

问题出在我的启动文件上

原来是这样的

services.AddMvc(config =>
{
    var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
});

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => {
    options.Cookie.Name = "RememberMeBlogAcademy";
    options.LoginPath = "/Account/LogIn";
    //options.LogoutPath = "/Home/Index";
    //options.AccessDeniedPath = "AccessDenied";
    options.ExpireTimeSpan = TimeSpan.FromDays(30);
    options.SlidingExpiration = true; // the cookie would be re-issued on any request half way through the ExpireTimeSpan
    //options.Cookie.Expiration = TimeSpan.FromDays(5);
    options.EventsType = typeof(CookieAuthEvent);
});
//services.AddScoped<CookieAuthEvent>();

 services.AddControllersWithViews();

问题在于一起使用 MVC 和 AddControllersWithViews。我不知道这会产生问题。

但是,应该是这样的——使用AddControllersWithViews

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => {
            options.Cookie.Name = "RememberMeBlogAcademy";
            options.LoginPath = "/Account/LogIn";
            //options.LogoutPath = "/Home/Index";
            //options.AccessDeniedPath = "AccessDenied";
            options.ExpireTimeSpan = TimeSpan.FromDays(30);
            options.SlidingExpiration = true; // the cookie would be re-issued on any request half way through the ExpireTimeSpan
            //options.Cookie.Expiration = TimeSpan.FromDays(5);
            options.EventsType = typeof(CookieAuthEvent);
});
services.AddScoped<CookieAuthEvent>();

services.AddControllersWithViews(config =>
{
     var policy = new AuthorizationPolicyBuilder()
         .RequireAuthenticatedUser()
         .Build();
     config.Filters.Add(new AuthorizeFilter(policy));
});

此外,您不需要从 cookie 中检索数据,如上面的Controller/UserProfile所示。

此外,当我进行调试以检查代码时,我测试了注销,以确保我确实从 cookie 而不是从 UserManager 检索用户数据,并且它确实运行良好。

这里是logOut的附加代码

[Authorize]
public async Task<IActionResult> Logout()
{
    await signInManager.SignOutAsync();
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    return RedirectToAction("Index", "Home");
}

0
投票

嘿,感谢分享解决方案。 您可以分享您的 CookieAuthEvent 吗? 因为我不知道那是什么。


-1
投票

获取cookie值

var cookie = Request.Cookies["cookieName"]; 
© www.soinside.com 2019 - 2024. All rights reserved.