问题
I'm using IdentityServer4 with ASP.NET Core 2.2. On the Post Login method I have applied the ValidateAntiForgeryToken. Generally after 20 minutes to 2 hours of sitting on the login page and then attempting to login it produces a blank page.
If you look at Postman Console you get a 400 Bad Request message. I then set the Cookie Expiration on the AntiForgery options to 90 days. I was able to allow the page to sit for up to 6 hours and still login. However, after around 8 hours (overnight), I received the blank page again after attempting to login.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login
services.AddAntiforgery(options =>
{
options.Cookie.Expiration = TimeSpan.FromDays(90);
});
I expect to be able to sit on the login page for 90 days which is the duration of the cookie but that doesn't work. How do I get the cookie for the AntiforgeryToken to last the entire 90 days or whatever time I set it to and not timeout or expire? Is there a way to catch this error and redirect the user back to the login method?
回答1:
Yet another implementation using the default one including all prechecks, logging etc. And it's still an AuthorizationFilter
, so that prevents any further action execution. The only difference is that it triggers HttpGet
to the same url instead of the default 400 response, a kind of the Post/Redirect/Get pattern implementation.
public class AnotherAntiForgeryTokenAttribute : TypeFilterAttribute
{
public AnotherAntiForgeryTokenAttribute() : base(typeof(AnotherAntiforgeryFilter))
{
}
}
public class AnotherAntiforgeryFilter:ValidateAntiforgeryTokenAuthorizationFilter,
IAsyncAuthorizationFilter
{
public AnotherAntiforgeryFilter(IAntiforgery a, ILoggerFactory l) : base(a, l)
{
}
async Task IAsyncAuthorizationFilter.OnAuthorizationAsync(
AuthorizationFilterContext ctx)
{
await base.OnAuthorizationAsync(ctx);
if (ctx.Result is IAntiforgeryValidationFailedResult)
{
// the next four rows are optional, just illustrating a way
// to save some sensitive data such as initial query
// the form has to support that
var request = ctx.HttpContext.Request;
var url = request.Path.ToUriComponent();
if (request.Form?["ReturnUrl"].Count > 0)
url = $"{url}?ReturnUrl={Uri.EscapeDataString(request.Form?["ReturnUrl"])}";
// and the following is the only real customization
ctx.Result = new LocalRedirectResult(url);
}
}
}
回答2:
This was my final solution. I added a attribute using the IAntifogery dependency injection.
public class CustomValidationAttribute : ActionFilterAttribute
{
private IAntiforgery _antiForgery { get; }
public CustomValidationAttribute(IAntiforgery antiforgery)
{
_antiForgery = antiforgery;
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var isRequestValid = await this._antiForgery.IsRequestValidAsync(context.HttpContext);
if (!isRequestValid)
{
//Add Code here if token is not valid
return;
}
await next();
}
}
Add the attribute to your controller methods that also use [HttpPost]
[TypeFilter(typeof(CustomValidationAttribute))]
回答3:
Slight modification to d_f code https://stackoverflow.com/a/56383473/841898 Instead of page redirect we just add error to ModelState. Then we display in model state summary.
public class CustomAntiForgeryTokenAttribute : TypeFilterAttribute
{
public CustomAntiForgeryTokenAttribute() : base(typeof(AnotherAntiforgeryFilter))
{
}
}
public class AnotherAntiforgeryFilter : ValidateAntiforgeryTokenAuthorizationFilter,
IAsyncAuthorizationFilter
{
public AnotherAntiforgeryFilter(IAntiforgery a, ILoggerFactory l) : base(a, l)
{
}
async Task IAsyncAuthorizationFilter.OnAuthorizationAsync(
AuthorizationFilterContext ctx)
{
await base.OnAuthorizationAsync(ctx);
if (ctx.Result is IAntiforgeryValidationFailedResult)
{
ctx.ModelState.AddModelError("Token", "Validation Token Expired. Please try again");
ctx.Result = null;
}
}
}
来源:https://stackoverflow.com/questions/56295076/antiforgerytoken-expiration-blank-page