ฉันมีปัญหาเดียวกันกับแอปพลิเคชัน ASP.NET MVC Core แบบหน้าเดียว ฉันแก้ไขได้โดยการตั้งค่าHttpContext.User
ในการดำเนินการของคอนโทรลเลอร์ทั้งหมดซึ่งเปลี่ยนการอ้างสิทธิ์ข้อมูลประจำตัวในปัจจุบัน (เนื่องจาก MVC ทำสิ่งนี้สำหรับคำขอที่ตามมาเท่านั้นตามที่กล่าวไว้ที่นี่ ) ฉันใช้ตัวกรองผลลัพธ์แทนมิดเดิลแวร์เพื่อต่อท้ายคุกกี้ป้องกันการปลอมแปลงในการตอบกลับของฉันซึ่งตรวจสอบให้แน่ใจว่าพวกเขาถูกสร้างขึ้นหลังจากการดำเนินการ MVC กลับมาแล้วเท่านั้น
คอนโทรลเลอร์ (NB ฉันกำลังจัดการผู้ใช้ด้วย ASP.NET Core Identity):
[Authorize]
[ValidateAntiForgeryToken]
public class AccountController : Controller
{
private SignInManager<IdentityUser> signInManager;
private UserManager<IdentityUser> userManager;
private IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory;
public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory)
{
this.signInManager = signInManager;
this.userManager = userManager;
this.userClaimsPrincipalFactory = userClaimsPrincipalFactory;
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(string username, string password)
{
if (username == null || password == null)
{
return BadRequest(); // Alias of 400 response
}
var result = await signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false);
if (result.Succeeded)
{
var user = await userManager.FindByNameAsync(username);
// Must manually set the HttpContext user claims to those of the logged
// in user. Otherwise MVC will still include a XSRF token for the "null"
// user and token validation will fail. (MVC appends the correct token for
// all subsequent reponses but this isn't good enough for a single page
// app.)
var principal = await userClaimsPrincipalFactory.CreateAsync(user);
HttpContext.User = principal;
return Json(new { username = user.UserName });
}
else
{
return Unauthorized();
}
}
[HttpPost]
public async Task<IActionResult> Logout()
{
await signInManager.SignOutAsync();
// Removing identity claims manually from the HttpContext (same reason
// as why we add them manually in the "login" action).
HttpContext.User = null;
return Json(new { result = "success" });
}
}
ตัวกรองผลลัพธ์เพื่อต่อท้ายคุกกี้ต่อต้านเชื้อรา:
public class XSRFCookieFilter : IResultFilter
{
IAntiforgery antiforgery;
public XSRFCookieFilter(IAntiforgery antiforgery)
{
this.antiforgery = antiforgery;
}
public void OnResultExecuting(ResultExecutingContext context)
{
var HttpContext = context.HttpContext;
AntiforgeryTokenSet tokenSet = antiforgery.GetAndStoreTokens(context.HttpContext);
HttpContext.Response.Cookies.Append(
"MyXSRFFieldTokenCookieName",
tokenSet.RequestToken,
new CookieOptions() {
// Cookie needs to be accessible to Javascript so we
// can append it to request headers in the browser
HttpOnly = false
}
);
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
Startup.cs แตก:
public partial class Startup
{
public Startup(IHostingEnvironment env)
{
//...
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddAntiforgery(options =>
{
options.HeaderName = "MyXSRFFieldTokenHeaderName";
});
services.AddMvc(options =>
{
options.Filters.Add(typeof(XSRFCookieFilter));
});
services.AddScoped<XSRFCookieFilter>();
//...
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
//...
}
}