【问题标题】:.NET Core 3.1 Authentication Cookie Lost After Very Short Time.NET Core 3.1 身份验证 Cookie 在很短的时间后丢失
【发布时间】:2021-12-12 05:29:39
【问题描述】:

这个项目仍在开发中,可以在我的开发笔记本电脑上完美运行,但是,当我发布到我的共享托管 Web 服务器 (Winserve) 时,功能就会中断。

旁注:我确信这在几周前运行良好,但我可能错了,因为我大部分时间都在我的开发笔记本电脑上运行它。

我有一个基本的 asp.net Core 3.1 Web 应用程序。我在 startup.cs 文件的 Configure() 和 ConfigureServices() 部分中添加了 Cookie 和身份验证信息。

我可以在 PROD 中登录应用程序,并且我的身份验证 cookie 似乎设置正确,它正确地从数据库中获取角色并添加相关声明等,并为用户提供正确的角色。 我知道这一点是因为 UI 会根据 User.Identity.IsAuthenticated = true 以及 User.IsInRole("Some Role") 等是否发生变化。

但是,在(不一致的)时间段(通常大约 30-40 秒)之后,当我导航到需要对用户进行身份验证(使用 [Authorize] 限定)的页面(控制器/操作)时,我得到重定向回登录页面!不过,这不仅仅是重定向,用户要么已注销,要么 cookie 不再有效。我每 5 秒尝试一次,持续了大约 30 秒,之后碰巧回到“授权”网址,每次我被推回登录页面。

在这段时间内(30 到 40 秒之前),我可以导航到安全页面,让我心满意足。所有不同的页面,或者一个接一个,或者在导航之间留几秒钟的间隙,它仍然有效,直到它不起作用!

另外,我已经在浏览器检查器中检查了 Cookie,并且肯定会创建 Cookie,我认为它的默认到期日期约为 14 天。但无论如何,这都是未来的方式。

这是我的 Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews().AddRazorRuntimeCompilation().AddNewtonsoftJson();

            services.AddControllers().AddNewtonsoftJson();

            services.AddDistributedMemoryCache();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie(options =>
                                {
                                    options.LoginPath = "/Login";
                                });

            services.AddAuthorization();

            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromMinutes(30);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });

            services.AddMvc().AddNewtonsoftJson();

            services.AddRazorPages().AddNewtonsoftJson();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseRouting();

            app.UseSession();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "areas",
                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

        }

这是我的 HomeController 中的登录和注销方法...

public IActionResult Login(LoginViewModel model)
        {
            if (string.IsNullOrEmpty(model.Username) || string.IsNullOrEmpty(model.Password)) { model.Errors.Add("Must provide a Username & Password"); return View(model); }
            var _user = _authenticationBusinessService.AuthenticateUser(model.Username, model.Password);
            if (_user != null && _user.Id > 0) { return SignUserIn(model, _user); }
            else { model.Errors.Add("We're unable to authenticate you with the credentials provided"); }
            return View(model);
        }

        public IActionResult SignOut()
        {
            return SignUserOut();
        }

还有他们调用的方法……

   private IActionResult SignUserIn(LoginViewModel model, UserDTO user)
        {
            var _claims = new List<Claim>
            {
                //User identity information
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Id.ToString()),
                new Claim("FirstName", user.Person.FirstName),
                new Claim("Surname", user.Person.Surname)
            };
            //Roles/Permissions
            _claims.AddRange(user.UserPermissionMaps.Select(x => new Claim(ClaimTypes.Role, x.Permission.Description)));

            var _claimsIdenity = new ClaimsIdentity(_claims, CookieAuthenticationDefaults.AuthenticationScheme);
            var _authProperties = new AuthenticationProperties() { IsPersistent = true, AllowRefresh = true };
            var _claimsPrincipal = new ClaimsPrincipal(_claimsIdenity);
            HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, _claimsPrincipal, _authProperties);

            if (string.IsNullOrEmpty(model.ReturnURL))
            {
                model.ReturnURL = "/";
            }
            return Redirect(model.ReturnURL);
        }
        private IActionResult SignUserOut()
        {
            HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            HttpContext.Session.Clear();
            return RedirectToAction("Index");
        }

您需要获得授权才能访问的示例 Cotroller...

 [Area("Admin")]
    public class HomeController : Controller
    {
        [Authorize]
        public IActionResult Index()
        {
            return View();
        }
    }

【问题讨论】:

  • 我没有想到任何理论,但我发现在调试此类身份验证问题时有用的一件事是在 Microsoft.AspNetCore.Authentication 上下文中启用详细日志记录。您如何做到这一点取决于您的日志记录提供商。
  • 您的共享主机多久回收一次您的应用程序?您可以检查几件事。如果在内存会话/cookie 存储中使用,请检查它是否可以在回收利用中幸存下来。检查您是否将数据保护管道的密钥环存放在可以回收利用的地方。
  • @weichch 感谢您的意见。您是否暗示它可能与应用程序池有关?这不是会话而不是 Cookie 吗?我已经问过我的主人关于它多久回收一次的问题。只等回复。
  • @JackA。谢谢,我会看看我能用日志做些什么。我只是使用这些 .net 核心 Web 应用程序模板的默认记录器... public HomeController(ILogger logger)
  • 它可以是应用程序池或数据保护管道。如果您没有使用 cookie 存储,那么您的 cookie 将包含完整的身份验证票证,在这种情况下,它可以在应用程序池回收后继续存在。但是,cookie 在发送回客户端之前使用数据保护管道加密,管道必须维护密钥环并将其保存在永久位置,否则如果您稍后将其发送回,它无法解密任何 cookie。如果是这种情况,用户将未经授权并受到质疑。

标签: c# .net asp.net-core .net-core cookies


【解决方案1】:

感谢@weichch,我找到了解决问题的方法

我的廉价托管服务提供商设置的 AppPool 大小限制为 200MB

我的应用程序,当通过 VS 通过 IIS Express 加载时,达到 160-180MB 左右,然后相当快(例如,通过在我的管理部分做一些事情),超过 200MB,然后坐在 220- 230MB,并没有真正移动(所以这不是内存泄漏问题)。

我通过提供商将我的计划升级到 AppPool 可以达到 512MB 的计划,这完全解决了问题。从那以后它一直运行良好。

谢谢大家?

【讨论】:

    猜你喜欢
    • 2021-06-19
    • 2020-03-09
    • 1970-01-01
    • 2020-05-18
    • 2021-11-06
    • 1970-01-01
    • 2020-06-05
    • 2020-09-23
    • 2021-05-16
    相关资源
    最近更新 更多