.Net Core 2.x 用户会话意外退出共享主机

.Net Core 2.x User Session signs out on Shared Hosting unexpectedly

我正在使用 aspnetboilerplate.com's dotnet 核心模板。我想做的是将模板部署到共享主机 (windows) 服务器 运行ning Plesk(注意,我根本无法控制服务器)。

该模板在本地完美运行,可以登录、添加用户、角色等。将其部署到共享托管服务器时出现了一些问题,但问题解决得相对较快(针对 dotnet 核心进行配置,不得不转到 dotnet 核心2.1 因为服务器尚不支持 2.2)。

现在的问题是登录后,一分钟内我重定向到登录页面。我在使用 ASP.NET MVC5 时遇到了类似的问题,但是在 web.config 中提供了一个机器密钥并为会话数据使用数据库解决了这个问题。所以我推断它与 dotnet 应用程序存在相同的问题。

但是由于 dotnet 核心不使用机器密钥和 DataProtectionApis,因此需要一种不同的方法。

所以我尝试将 services.AddDataProtection(); 添加到 StartUp.Configure()

我已经阅读了 Distributed caching in ASP.NET Core 并且几乎所有的链接都在那里,并且尝试了多个代码示例,但是我不知道我在做什么(很可能)或者我没有做某事对。

那么,如何防止用户在共享托管服务器上使用 dotnet core 2.1 意外注销?

编辑 - 2019-01-25

一些新信息:已尝试按照建议设置超时,但这要么无济于事,要么不可能。对于 Plesk 上 运行 的 dotnet 应用程序,我必须禁用 ASP.NET 支持,以便 .NET 核心获得无托管代码应用程序池。尝试访问 Plesk 上的 ASP.Net 设置(您可以在其中访问应用程序池设置等)给出一个错误提示 'ASP.NET support is switched off for this website'。

有一件事不会发生,那就是发布时从未创建 App_Data/Logs 文件夹。我必须手动创建和设置权限,以便 log4net 可以创建日志文件。日志文件为我提供了更多信息:

ERROR 2019-01-25 09:33:03,005 [6    ] .Antiforgery.Internal.DefaultAntiforgery - An exception was thrown while deserializing the token.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted. ---> System.Security.Cryptography.CryptographicException: The key {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} was not found in the key ring.

仅再次搜索此错误导致我找到有关将 services.AddDataProtection() 添加到 ConfigureServices 方法的文档,但此无人机关于 Azure Key Vaults(或其他外部提供商)或将信息写入共享 UNC 所以其他服务器可以访问缓存的密钥信息(这可能是我需要的)。但鉴于我无法使用所有这些选项,我找到了一种扩展方法,它允许将密钥存储在 MSSQL 服务器上。现在忙着设置这个来测试。

如果有人想发表意见,请做客

更新 2 - 2019-01-25 - 成功(目前)

看来使用 DataProtectionAPI 是可行的方法。日志尚未报告任何 AntiforgeryValidationException。我打算让它 运行 一段时间,如果一切顺利,我将 post 解决方案及其实施方式。

根据您在上面提供的信息,我认为您的会话超时了。

当会话超时时,用户将被重定向到登录页面以重新进行身份验证。我对 plesk 不是很熟悉,但是从非常快速的谷歌搜索看来,您应该能够增加会话超时。

当然,如果您在 configurservices 中自己设置 sessiontimeout,我认为您也可以在那里进行调整(再次完全不熟悉 plesk 设置)。

如果您这样做,问题应该会自行解决。也许会话超时设置为测试的短时间?

.net 会话状态

services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
        });

问题,事实证明不是会话过期,而是当另一台服务器接管我的站点的负载时,它没有会话上下文。数据保护服务允许创建一个数据库来存储会话信息,并在场中的服务器之间共享。类似于 MVC 项目中 web.config 的会话状态属性:

<sessionState mode="SQLServer" sqlConnectionString="Data Source=000.000.000.000;Initial Catalog=session_db;User Id=user;Password=password;" allowCustomSqlDatabase="true" timeout="480" />

我是这样解决问题的:

我在 ConfigureServices 中添加了:

services.AddDataProtection()
            .SetApplicationName("MyApplicationName")
            .SetDefaultKeyLifetime(TimeSpan.FromDays(14)) 
            .PersistKeysToSqlServer(_config["DataProtection:SqlServerConnectionString"]);

我还必须创建一个单独的数据库来负责存储会话信息。 DataProtextion:SqlServerConnectionStringappsettings.json 文件中的一个条目:

"DataProtection":
    {
        "SqlServerConnectionString": "Server=server; Database=database; User=user; Password=password;"
    }

可能有一些方法可以解决这个问题(例如使用 Redis),但鉴于我无法控制我的网站所在的服务器,数据保护服务工作得很好。

由于 dot net core 3.1 不支持 PersistKeysToSqlServer,我们可以使用 .PersistKeysToDbContext<AppDBContext>()PersistKeysToFileSystem,如图所示 here