[英]ASP.NET Core 6: Setting session timeout does not work
我正在尝试调整我的 .NET Core 6 项目以使用非默认的 session 超时。
按照 Microsoft.com 上的说明,我尝试将以下内容添加到我的 Program.cs 中:
//This should cause me to time out after 1 minute. It does not
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(
options => {
options.Cookie.Name = ".MyWebsite.Session";
options.IdleTimeout = TimeSpan.FromMinutes(1);
options.Cookie.IsEssential = true;
});
app.UseSession();
有什么我想念的吗? 我想增加 session 过期所需的时间。 根据上面的代码,当我登录程序时,我的 session 应该在 1 分钟后过期。 确实如此。 如果我将时间设置为 4 小时,则相同。 无论我使用什么设置,它似乎都迫使我在 20 分钟左右注销。
如果重要的话,该项目是从 .NET Core 3.1 迁移而来的。
以下是 Program.cs 文件中的完整代码:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("MyConnection");
builder.Services.AddDbContext<DBContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(
options => {
options.Cookie.Name = ".MyWebsite.Session";
options.IdleTimeout = TimeSpan.FromMinutes(1);
options.Cookie.IsEssential = true;
});
//Add JWT bearer and denied paths
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Unauthorized/";
options.AccessDeniedPath = "/Account/Forbidden/";
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("Jwt:Key"))
};
});
//GDPR compliance
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
builder.Services.ConfigureNonBreakingSameSiteCookies();
builder.Services.ConfigureApplicationCookie(options =>
{
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = x =>
{
x.Response.Redirect("https://localhost:44329/Expired/Index/000");
return Task.CompletedTask;
}
};
options.ExpireTimeSpan = TimeSpan.FromDays(14);
options.SlidingExpiration = true;
});
//define policy for different authorization
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Administrator"));
options.AddPolicy("UsersOnly", policy => policy.RequireRole("User", "Editor", "Administrator"));
options.AddPolicy("RequireApprovedUser", policy => policy.Requirements.Add(new ApprovedUserRequirement(true)));
});
builder.Services.AddScoped<IAuthorizationHandler, ApprovedUserRequirementHandler>();
//Data Protection configuration
var keysFolder = Path.Combine(builder.Environment.ContentRootPath, "Keys");
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(6);
options.Lockout.MaxFailedAccessAttempts = 5;
options.SignIn.RequireConfirmedAccount = true;
})
.AddDefaultTokenProviders()
.AddDefaultUI()
.AddEntityFrameworkStores<DBContext>();
builder.Services.AddRazorPages();
builder.Services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, UserClaimsPrincipalFactory<IdentityUser, IdentityRole>>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode >= 400)
{
context.Request.Path = "/Error/Index/" + context.Response.StatusCode;
await next();
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
使用 cookie 身份验证时,仅当调用HttpContext.Authentication.SignInAsync
时我们传入一个IsPersistent
设置为true
的AuthenticationProperties
实例时,才使用ExpireTimeSpan
属性。
因此,您可能希望 cookie 在浏览器会话中持续存在。 只有在用户明确同意并在登录时使用“记住我”复选框或类似机制时,才应启用这种持久性。 代码如下:
// using Microsoft.AspNetCore.Authentication;
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties
{
IsPersistent = true
});
此外,您还可以设置绝对 cookie 过期时间。 以下代码片段创建一个持续 20 分钟的身份和相应的 cookie。 这会忽略之前配置的任何滑动过期设置。
// using Microsoft.AspNetCore.Authentication;
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
});
更多详细信息,请参阅持久性 cookies 。
好吧,我终于想通了。 事实证明,使用会话进行身份验证 cookies 是行不通的。 可能是我在其他地方做过的事情。
我使用以下命令强制我的 cookies 的生命周期为 1 分钟:
builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = ".AspNetCore.Identity.Application";
options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
options.Cookie.MaxAge = TimeSpan.FromMinutes(1);
options.SlidingExpiration = true;
});
这里的关键是使用options.Cookie.MaxAge
除了options.ExpireTimeSpan
。
现在给用户超过 20 多分钟的默认时间要容易得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.