AntiForgeryToken Expiration Blank Page

后端 未结 3 1516
情书的邮戳
情书的邮戳 2021-02-20 03:17

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 l

相关标签:
3条回答
  • 2021-02-20 03:30

    Update '2021

    Since ASP.Net Core 3.0 MS decided to make ValidateAntiforgeryTokenAuthorizationFilter internal. Now we have to copy-paste their code, to be able to derive. But most likely we don't need to. To just change the resulting behavior all we need is to test the context for the IAntiforgeryValidationFailedResult and proceed accordantly, as described in this example.

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Core.Infrastructure;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace BasicWebSite.Filters
    {
        public class RedirectAntiforgeryValidationFailedResultFilter : IAlwaysRunResultFilter
        {
            public void OnResultExecuting(ResultExecutingContext context)
            {
                if (context.Result is IAntiforgeryValidationFailedResult result)
                {
                    context.Result = 
                        new RedirectResult("http://example.com/antiforgery-redirect");
                }
            }
    
            public void OnResultExecuted(ResultExecutedContext context)
            { }
        }
    }
    

    Then within the controller:

    // POST: /Antiforgery/LoginWithRedirectResultFilter
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    [TypeFilter(typeof(RedirectAntiforgeryValidationFailedResultFilter))]
    public string LoginWithRedirectResultFilter(LoginViewModel model)
    {
        return "Ok";
    }
    

    The original answer covering .net core 2.2

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-20 03:46

    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))]
    
    0 讨论(0)
  • 2021-02-20 03:50

    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;
    
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题