ASP.NET 会话 Cookie 未设置

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

未设置 ASP.NET Core 会话 Cookie 的问题(间歇性)

我正在使用 ASP.NET Core 会话,由于某种原因,中间件没有始终如一地发送

Set-Cookie
cookie 的
.AspNetCore.Session
标头。这个问题变得更加奇怪,因为有时它工作得很好,但有时却不行。

例如,在 DevMachine1 上,它当前不起作用,但如果我转到 DevMachine2 并使用相同的中间件配置运行完全相同的存储库,它会按预期工作。

问题背景:

Program.cs

builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
builder.Services.AddControllersWithViews();
builder.Services.AddScoped<AutomateAPIService>();
builder.Services.AddScoped<AutomateDataService>();
// builder.Services.AddSingleton<PersistService>(); // For Future Persist Integration, removing to test sessions.
builder.Services.AddScoped<AutomateLoginService>();
builder.Services.AddTransient<JsonParserService>();
builder.Services.AddSingleton<IMongoClient, MongoClient>(sp => new MongoClient(connectionUri));
builder.Services.AddTransient<PersistService>();
builder.Services.AddTransient<SessionValidationService>();
builder.Services.AddScoped<SessionAuthorizationFilter>();
builder.Services.AddScoped<DeviceJsonParser>();
builder.Services.AddDistributedMemoryCache();

// MongoSessionStorage
builder.Services.AddSingleton(sp =>
{
    var client = sp.GetRequiredService<IMongoClient>();
    var database = client.GetDatabase("SessionDatabase");
    return database.GetCollection<BsonDocument>("Sessions");
});

// Add Session
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(60);
    options.Cookie.SecurePolicy = CookieSecurePolicy.None;
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
    options.Cookie.SameSite = SameSiteMode.Lax;
});

builder.Services.AddSingleton<ISessionStore, MongoDbSessionStore>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseSession();
app.UseAuthorization();

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

app.Run();

您可能会注意到,会话存储在 MongoDB 数据库中。此设置以前曾有效,并且在某些机器上仍然间歇性地工作。 回滚到内存缓存也没有解决问题。

日志:

我们退出会话存储并看到以下内容:

Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Setting SessionKey, System.Byte[] for session
info: WebAppApiTest.Controllers.HomeController[0]
      SessionKey value: SessionValue
info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Attempting to commit session ca2084a4-23c1-f13f-4bb2-661251e14d38
info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Session ca2084a4-23c1-f13f-4bb2-661251e14d38 committed successfully. Matched: 0, modified 0, Upserted: True

我们可以看到会话 ID,因此我们知道中间件正在工作在一定程度上,但没有设置会话 cookie,这意味着我们的会话存储永远没有正确或持久的会话 ID 可供参考。

强制会话交互的控制器测试:

我尝试在我的

LoginController
上强制进行会话交互,看看是否可以让 ASP.NET 发送会话 cookie:

public IActionResult AutomateLogin()
{
    HttpContext.Session.SetString("SessionKey", "SessionValue"); 
    var sessionValue = HttpContext.Session.GetString("SessionKey");
    _logger.LogInformation($"SessionKey value: {sessionValue}");
    return View(new AutomateLoginModel());
}

日志确认会话交互正在发生:

info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Setting SessionKey, System.Byte[] for session
info: WebAppApiTest.Controllers.AutomateLoginController[0]
      SessionKey value: SessionValue
info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Attempting to commit session 6207e6cb-6eeb-688e-0e37-c60e32f4a004
info: WebAppApiTest.Services.MongoDbSessionStore[0]
      Session 6207e6cb-6eeb-688e-0e37-c60e32f4a004 committed successfully. Matched: 0, modified 0, Upserted: True

仍然,没有设置会话cookie

问题摘要:

  • 会话 cookie 未在不同的机器上、在不同的时间间歇性地设置。
  • 正在生成会话 ID 并将其提交到存储(MongoDB 或内存中,问题仍然存在)。
  • 工作环境和非工作环境中的中间件配置是相同的。
  • 我希望在每个新会话中设置会话 cookie。
我的问题:

设置会话 cookie (

.AspNetCore.Session) 时,什么可能导致 ASP.NET Core 会话

 间歇性失败?即使配置相同,为什么会在某些计算机上设置会话 cookie 而在其他计算机上则不设置?

我确实在多个浏览器上验证了这一点,并确认 Set-Cookie 标头不存在。我确实找到了原因:

因此,在 SessionMiddleware 类中,我们评估是否应该在此处包含标头:

重要更新:

在 SessionMiddleware.cs(一个 ASP.NET 本机类)中

Set-Cookie 标头根据响应是否启动进行有条件评估。如果响应已经开始,我们就不能再使用 Set-Cookie 标头。

但是,运行一段时间的调试后,看起来即使我的响应 HasStarted value = false,我们也没有设置 _shouldEstablishSession = true。

会话中间件.cs

internal bool TryEstablishSession() { return (_shouldEstablishSession |= !_context.Response.HasStarted); }
当我在返回线上设置断点时,它根本没有被击中,所以即使我的 Response.HasStarted 为 false,因此 _shouldbuiltSession 应该为 true

private static Task OnStartingCallback(object state) { var establisher = (SessionEstablisher)state; if (establisher._shouldEstablishSession) { establisher.SetCookie(); } return Task.CompletedTask; }
因此,在此任务中执行时,我们的 _shouldEstablishSession 值为 false。

不确定为什么它没有评估,但这肯定是不包含 Set-Cookie 标头的问题。可能是中间件管道问题,但不确定为什么它表现为间歇性问题。

c# asp.net asp.net-mvc asp.net-core-mvc
1个回答
0
投票
在查看了 ASP.NET Core 中负责创建和发送会话 cookie 的底层类后,我意识到方法

TryEstablishSession

 没有被调用。此方法对于设置会话 cookie 至关重要,应在创建会话时作为委托传递。

自定义会话存储中的

Create

 方法应如下所示:

public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSession) { return new MongoDbSession(sessionKey, _sessionCollection, idleTimeout, _logger, tryEstablishSession); }
一旦 

tryEstablishSession

 委托被传递给 
LoadAsync
CommitAsync
 等会话操作,会话 cookie 就开始正确设置。 
SessionMiddleware
类中的断点终于被命中,并且会话cookie包含在响应中。

修复:

tryEstablishSession

委托应在创建会话时传递并在整个会话生命周期中使用。这确保底层中间件可以调用它,从而允许设置会话 cookie。

虽然问题一开始是间歇性的,但此解决方案解决了问题,并且会话 cookie 现在已一致设置。

© www.soinside.com 2019 - 2024. All rights reserved.