我有同樣的問題用一個單頁的ASP.NET MVC的核心應用。我通過在所有控制器動作中設置HttpContext.User
來解決它,這些動作改變了當前的身份聲明(因爲MVC僅對後續請求執行此操作,如討論here)。我使用結果過濾器而不是中間件來將防僞cookie附加到我的響應中,這確保了它們僅在MVC操作返回後才生成。
控制器(注意:我使用ASP管理用戶。NET核心身份):
[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)
{
//...
}
}
你真的可以驗證@ Html.AntiForgeryToken代碼是否被調用而不重新加載嗎? – 2013-02-20 01:04:55
它肯定是,我可以成功打破那裏檢查HttpContext.Current.User對象,就像我提到的 – parliament 2013-02-20 05:59:02
請參閱:http://stackoverflow.com/a/19471680/193634 – 2014-01-23 05:27:22