【发布时间】:2020-10-02 07:03:18
【问题描述】:
我正在运行一个使用 ASP.NET 核心 3.1.8 的网站,使用 MS Identity 框架。 效果很好,网站已经上线一年了。 我想在电子邮件中向用户提供一个链接,然后当他们单击该链接时,它会将他们带到一个需要他们登录才能查看的页面。中间件重定向到登录页面,用户登录,然后返回目标页面。
除非用户已经在他们的浏览器中打开了一个选项卡并且已经登录,否则这很好用。用户单击链接并被重定向到登录页面(不确定原因),然后他们登录到错误页面400 作为异常已被抛出: "防伪令牌验证失败。防伪cookie令牌和请求令牌不匹配"
如果我手动将该链接复制并粘贴到浏览器中,它不会重定向到登录页面,而是直接进入该页面(因为我已经登录),即使我只是在 Notepad++ 中编写 URL 和双击它,它直接进入页面。如果 URL 出现在 <a href="https://url-to-page">...</a> 中并且我单击它以将我带到我遇到问题的页面,这似乎只是一个问题。我确实想知道是否与跨站点起源相关并删除了 CORS 中间件并将 cookie 同站点规则更改为无,但这没有任何区别。
这是 Startup.cs 中的相关部分
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Strict;
});
if (HostingEnvironment.IsStaging())
{
// For migrations:
// Set environment variable ASPNETCORE_ENVIRONMENT to Staging for MariaDbContext
// $Env:ASPNETCORE_ENVIRONMENT = "Staging"
// Add-Migration -Context MariaDbContext <migration name>
services.AddDbContext<AppDbContext, MariaDbContext>();
}
else
{
// For migrations:
// Set environment variable ASPNETCORE_ENVIRONMENT to Staging for MariaDbContext
// $Env:ASPNETCORE_ENVIRONMENT = "Development"
// Add-Migration -Context AppDbContext <migration name>
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("IdentityContextConnection"));
});
}
services.Configure<RecaptchaSettings>(Configuration.GetSection("RecaptchaSettings"));
// Add singleton services
services.AddSingleton<IEmailSenderSTC, EmailSender>();
services.AddSingleton<ISimpleLogger, SimpleLoggerFile>(x => new SimpleLoggerFile(Configuration.GetValue<string>("LogFile"), LogLevel.Information));
// Add transient services
services.AddTransient<INewsRepository, NewsRepository>();
services.AddTransient<IGalleryRepository, GalleryRepository>();
services.AddTransient<ILadderRepository, LadderRepository>();
services.AddTransient<IFileSystem, FileSystem>();
services.AddTransient<ISettingsRepository, SettingsRepository>();
services.AddTransient<IClubSparkMembersRepository, ClubSparkMembersRepository>();
// Add environment specific services
if (HostingEnvironment.IsDevelopment())
{
services.AddSingleton<ISmarterMailRepository, SmarterMailRepoStub>();
services.AddTransient<IRecaptchaService, RecaptchaServiceStub>();
}
else if (HostingEnvironment.IsStaging())
{
services.AddTransient<ISmarterMailRepository, SmarterMailRepoStub>();
services.AddTransient<IRecaptchaService, RecaptchaServiceStub>();
}
else
{
services.AddTransient<ISmarterMailRepository, SmarterMailRepo>();
services.AddTransient<IRecaptchaService, RecaptchaService>();
}
// Staging environment is on Pi2 with HTTP only so cookie security policy needs to be relaxed
var cookieSecurePolicy = HostingEnvironment.IsStaging() ? CookieSecurePolicy.SameAsRequest : CookieSecurePolicy.Always;
services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.IsEssential = true;
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.SecurePolicy = cookieSecurePolicy;
});
services.AddIdentity<MemberIdentity, IdentityRole>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = true;
options.SignIn.RequireConfirmedEmail = true;
}).AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders()
.AddUserManager<AppUserManager>();
services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.LoginPath = "/Identity/Account/Login";
options.LogoutPath = "/Identity/Account/Logout";
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.SlidingExpiration = true;
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = cookieSecurePolicy;
options.Cookie.SameSite = SameSiteMode.Strict;
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.Events.OnRedirectToLogin = ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == StatusCodes.Status200OK)
{
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
return Task.CompletedTask;
};
});
services.Configure<CookieTempDataProviderOptions>(options =>
{
options.Cookie.IsEssential = true;
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = cookieSecurePolicy;
options.Cookie.SameSite = SameSiteMode.Strict;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddMemoryCache();
services.AddControllersWithViews();
services.AddRazorPages();
//services.AddMvc(options =>
//{
// options.EnableEndpointRouting = false;
//});
services.AddHsts(options =>
{
options.Preload = true;
options.MaxAge = TimeSpan.FromDays(365);
options.IncludeSubDomains = true;
});
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AppUserManager userManager,
RoleManager<IdentityRole> roleManager, AppDbContext context, ISettingsRepository settingsRepository)
{
if (!env.IsProduction())
context.Database.Migrate();
if (env.IsDevelopment() || env.IsStaging())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
if (!env.IsStaging())
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseCors("CorsPolicy");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseStatusCodePagesWithRedirects("/Error?code={0}");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
我有控制器,用于设置 URL 的位置,属性为 [Authorize],并且 Action 具有 [HttpGet] 属性
【问题讨论】:
-
我猜你的cookie无法通过的原因是根据你的cookie设置。我建议您可以尝试将
options.MinimumSameSitePolicy设置为无,然后重试。
标签: c# asp.net-core asp.net-core-mvc