You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 3.1 部署到共享主机后认证Cookie短时间内失效问题

问题原因

  1. 数据保护密钥未持久化配置:ASP.NET Core默认使用数据保护API加密认证Cookie,默认情况下密钥存储在进程内存中,共享托管环境下应用池会定期回收、或存在多实例负载均衡的情况,每次回收/切换实例都会生成新密钥,导致之前签发的Cookie无法被解密,直接判定为无效,用户被登出。这是最符合30-40秒失效场景的诱因,很多共享托管的应用池闲置回收时间设置得非常短,刚好吻合该失效周期。
  2. 分布式缓存配置错误:你配置了AddDistributedMemoryCache,这是进程内的内存缓存,仅适合单实例开发环境使用,共享托管多实例/应用池回收后缓存内容全部丢失,若Cookie认证的会话相关校验依赖该缓存就会失效。
  3. 中间件顺序错误:Configure方法中的中间件执行顺序不符合规范,你将UseHttpsRedirection、UseStaticFiles放在了身份认证和授权中间件之后,会导致请求在还没完成HTTPS跳转时就进入认证逻辑,可能出现Cookie跨协议不匹配、认证上下文丢失的问题。
  4. 异步方法未等待:SignUserIn方法中调用异步方法HttpContext.SignInAsync时没有使用await关键字,也未将方法标记为async Task<IActionResult>,异步操作未完成就提前返回重定向,可能导致Cookie签发不完全,出现偶发的认证失效。

解决方案

  • 配置数据保护密钥持久化:在ConfigureServices方法中添加数据保护配置,将密钥存储到共享托管允许读写的本地目录,确保应用池回收、实例切换后密钥不会丢失,示例代码:
services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"你的站点可读写目录路径\DataProtection-Keys"))
    .SetApplicationName("你的应用名称");

注意要确保配置的目录站点运行身份有读写权限。

  • 替换分布式缓存实现:如果是共享托管单实例场景,可以直接移除AddDistributedMemoryCache的配置,或者如果后续要扩展多实例,改用共享的分布式缓存实现比如Redis、SqlServer分布式缓存。
  • 修正中间件顺序:将Configure方法中的中间件调整为正确的执行顺序,修改后代码如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    // 调整顺序:先HTTPS重定向
    app.UseHttpsRedirection();
    // 再处理静态文件
    app.UseStaticFiles();
    // 再路由
    app.UseRouting();
    // 再Session
    app.UseSession();
    // 再认证、授权
    app.UseAuthentication();
    app.UseAuthorization();

    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?}");
    });
}
  • 修复异步方法调用:将SignUserIn和SignUserOut方法改为异步实现,等待异步方法执行完成:
private async Task<IActionResult> SignUserIn(LoginViewModel model, UserDTO user)
{
    // 原有生成Claims等逻辑不变
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, _claimsPrincipal, _authProperties);
    // 原有重定向逻辑不变
}

private async Task<IActionResult> SignUserOut()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    HttpContext.Session.Clear();
    return RedirectToAction("Index");
}
// 对应的Login和SignOut方法也要改为异步:
public async Task<IActionResult> Login(LoginViewModel model)
{
    // 原有逻辑不变
    if (_user != null && _user.Id > 0) { return await SignUserIn(model, _user); }
    // 原有逻辑不变
}

public async Task<IActionResult> SignOut()
{
    return await SignUserOut();
}

内容的提问来源于stack exchange,提问作者Kevin Dark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 19:45:07