如何使用MVC6 RC1 RC2中的IAuthorizationFilter验证Ajax头中的Antiforgery令牌

时间:2016-05-17 19:53:38

标签: asp.net-mvc authorization authorize-attribute

如果你使用RC2忽略了所有过滤器代码,那么你需要做的就是

StartUp.cs

  services.AddAntiforgery(options => options.HeaderName = "YOUR_HEADER_NAME");

适用于RC1

之前我使用IAuthorization过滤器来验证AntiForgery令牌,但似乎MVC6中的事情发生了巨大变化。我找不到任何描述过滤更改的文档。

这是我的旧代码

  [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class CustomValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    // why is this necessary..
    // take a look here http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-%28csrf%29-attacks
    // the CSRF token is inserted into the AJAX header
    //
    public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
    {
        if (actionContext == null)
        {
            throw new ArgumentNullException("actionContext");
        }
        if (continuation == null)
        {
            throw new ArgumentNullException("continuation");
        }

        try
        {
            // insanely easy -- just extart the cookie token and the headertoken - it they are null who cares the validation will fail
            var headerToken = actionContext.Request.Headers.GetValues("__RequestVerificationToken").FirstOrDefault(); // ajax headers
            var cookieToken = actionContext.Request.Headers.GetCookies().Select(s => s[AntiForgeryConfig.CookieName]).FirstOrDefault();

            AntiForgery.Validate(cookieToken.Value, headerToken);
        }
        catch (HttpAntiForgeryException)
        {
            actionContext.Response = new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.Forbidden,
                RequestMessage = actionContext.ControllerContext.Request
            };
            return FromResult(actionContext.Response);
        }
        return continuation();
    }

    private Task<HttpResponseMessage> FromResult(HttpResponseMessage result)
    {
        var source = new TaskCompletionSource<HttpResponseMessage>();
        source.SetResult(result);
        return source.Task;
    }
}

 [Authorize]
public class SubmissionController : ApiController
{
    [CustomValidateAntiForgeryToken] // note this is a custom filter, named to clarify its not the built in one as thats for views!
    public HttpResponseMessage Delete(int? ID)  {.. blah ..}
  • 在MVC6中实现相同功能的推荐方法是什么?
  • 有人能指出我的文件吗?

由于

1 个答案:

答案 0 :(得分:1)

以下是基于MVC文档的示例实现。

public class ValidateAntiForgeryHeaderToken : TypeFilterAttribute
{
    public ValidateAntiForgeryHeaderToken() : base(typeof(ValidateAntiForgeryHeaderTokenImpl))
    {
    }

    // see https://docs.asp.net/en/latest/mvc/controllers/filters.html
    //
    // If you have a simple filter that doesn’t require any arguments, but which has constructor dependencies that need to be filled by DI, 
    // you can inherit from TypeFilterAttribute, allowing you to use your own named attribute on classes and methods (instead of [TypeFilter(typeof(FilterType))]). 
    //

    private class ValidateAntiForgeryHeaderTokenImpl : IAsyncAuthorizationFilter
    {
        private readonly IAntiforgery _antiforgery; 

        public readonly string verificationToken = "X-VerificationToken";
        public readonly string antiforgeryCookieName;

        public ValidateAntiForgeryHeaderTokenImpl(IAntiforgery antiforgery, IOptions<AntiforgeryOptions> antiforgeryOptions)
        {
            _antiforgery = antiforgery;
            antiforgeryCookieName = antiforgeryOptions.Value.CookieName; // if not specified this is autogenerated by mvc
        }

        public Task OnAuthorizationAsync(AuthorizationContext context)
        {
            string headerToken = context.HttpContext.Request.Headers[verificationToken];
            if (headerToken != null)
            {                     
                string antiForgeryCookieValue = context.HttpContext.Request.Cookies[antiforgeryCookieName];
                _antiforgery.ValidateTokens(context.HttpContext, new AntiforgeryTokenSet(headerToken, antiForgeryCookieValue)); // throws on invalid 
                return Task.FromResult<object>(null);
            }
            return _antiforgery.ValidateRequestAsync(context.HttpContext);               
        }
    }
}

装饰你的控制器/动作

    [HttpPost]
    [ValidateAntiForgeryHeaderToken]
    public IActionResult Add([FromBody] someObject data )
    {
        // Why Frombody??  https://lbadri.wordpress.com/2014/11/23/web-api-model-binding-in-asp-net-mvc-6-asp-net-5/
    }

并在您的AJAX调用中,将从@ Html.AntiForgeryToken()生成的令牌放入请求标头中。

$.ajax({
type: 'POST',
url: '@Url.Action("yourAction", "yourController", new { Area = "yourArea" })',
dataType: "json",
contentType: "application/json",
data: JSON.stringify(data),
headers: {
    'X-VerificationToken': $("[name='__RequestVerificationToken']").val()
},