我有一个ASP.NET Core API \ Angular应用程序。我的API需要支持cookie和令牌。
使用我的服务登录后,返回的防伪标记无效,因为它是基于空用户创建的。我尝试在PasswordSignInAsync之后设置ClaimsPrincipal并重新生成防伪令牌(见下文),但仍然无法正常工作。有任何想法吗?
public virtual async Task<IActionResult> Login([FromBody] AccountLoginModel model)
{
var result = await this.SignInManager.PasswordSignInAsync(model.Email, model.Password, isPersistent: model.RememberMe, lockoutOnFailure: false);
if (!result.Succeeded)
{
return this.BadRequest();
}
var user = await this.UserManager.FindByEmailAsync(model.Email);
// 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 this.PrincipalFactory.CreateAsync(user);
this.HttpContext.User = principal;
// Update XSRF token
var tokens = this.Antiforgery.GetAndStoreTokens(this.HttpContext);
return this.Ok();
}
ASP.Net Core 2.2显然会有一个"recommended" approach。
但在那之前,这就是我想出来的:https://github.com/aspnet/Home/issues/2783#issuecomment-422322294
我没有使用Angular,但我正在使用具有相同“读取cookie,写入标头”支持的Axios HTTP客户端。所以这不是使用Angular测试的,而是使用相同的cookie和标题名称。
我对它并不完全满意,因为感觉就像手动设置HttpContext.User相当......糟糕。
我创建了一个ResultFilterAction,它将在Controller Actions运行后设置cookie。灵感:https://github.com/aspnet/Home/issues/2415#issuecomment-354674201
public class AntiforgeryCookieResultFilterAttribute : ResultFilterAttribute
{
protected IAntiforgery Antiforgery { get; set; }
public AntiforgeryCookieResultFilterAttribute(IAntiforgery antiforgery) => this.Antiforgery = antiforgery;
public override void OnResultExecuting(ResultExecutingContext context)
{
var tokens = this.Antiforgery.GetAndStoreTokens(context.HttpContext);
context.HttpContext.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
}
}
我在Startup.cs中把它搞定了:
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
services.AddTransient<AntiforgeryCookieResultFilterAttribute>();
services
//AJ: See above for more information about AntiForgeryTokens.
.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
options.Filters.AddService<AntiforgeryCookieResultFilterAttribute>();
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
{...}
}
最后,一行需要添加到Login和Logout操作以确保设置了HttpContext.User。
登录:HttpContext.User = await signInManager.CreateUserPrincipalAsync(user);
退出:HttpContext.User = new ClaimsPrincipal();