Saya memiliki masalah yang sama dengan aplikasi ASP.NET MVC Core satu halaman. Saya mengatasinya dengan menetapkan HttpContext.User
dalam semua tindakan pengontrol yang mengubah klaim identitas saat ini (karena MVC hanya melakukan ini untuk permintaan berikutnya, seperti yang dibahas di sini ). Saya menggunakan filter hasil alih-alih middleware untuk menambahkan cookie antiforgery ke respons saya, yang memastikan bahwa itu hanya dihasilkan setelah tindakan MVC kembali.
Pengontrol (NB. Saya mengelola pengguna dengan 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" });
}
}
Filter hasil untuk menambahkan cookie antiforgery:
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)
{
}
}
Ekstrak 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)
{
//...
}
}