質問

Hello I'm following this tutorial:

And I'm trying to send Ajax request which include AntiforgeryToken. Here my ajax request:

$(document).ready(function () {
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }
    $('.z').on('click', function (event) {
        event.preventDefault();
        $.ajax({
            url: "/DeviceUsage/Return",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: 'html',
            headers: {
                'RequestVerificationToken': '@TokenHeaderValue()'
            },
            data: JSON.stringify({ dev: { DeviceInstanceId: $('#DeviceInstanceId').val(), UserId: "1", StorageId: $('#StorageId').val() } }),
            error: function (data) {
                alert("wystąpił nieokreślony błąd " + data);
            },
            success: function (data) {
                $('.modal-body').html(data);
            }
        })
    })
});

here my controller:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Return(DeviceUsage dev)
    {
        if(dev.StorageId==3)
        {
            ModelState.AddModelError("", "Nie można oddać na własne biurko");
            ViewBag.StorageId = new SelectList(unitOfWork.storageRepository.Get(), "Id", "Name", dev.StorageId);
            return PartialView(dev);
        }
        dev.UserId = 1;
        unitOfWork.deviceUsageRepository.Update(dev);
        unitOfWork.Save();
        return RedirectToAction("MyDevices");
    }

But in this tutorial they show function like:

void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";

IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
    string[] tokens = tokenHeaders.First().Split(':');
    if (tokens.Length == 2)
    {
        cookieToken = tokens[0].Trim();
        formToken = tokens[1].Trim();
    }
}
AntiForgery.Validate(cookieToken, formToken);
}

But I have no idea where to put this code in my controller and how to call this function. Can anyone explain me how to use above code?

役に立ちましたか?

解決

What they are showing in Anti-CSRF and AJAX section of the tutorial is a non-standard token validation method. In this example you would not use [ValidateAntiForgeryToken], but rather run the validation manually. Firstly you inject additional header in ajax call:

        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        },

and then read and validate token from the header in your action:

[HttpPost]
public ActionResult Return(DeviceUsage dev)
{
    ValidateRequestHeader(Request);
    //process action
}
void ValidateRequestHeader(HttpRequestBase request)
{
    string cookieToken = "";
    string formToken = "";

    if (request.Headers["RequestVerificationToken"] != null)
    {
        string[] tokens = request.Headers["RequestVerificationToken"].Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}

Notice that ValidateRequestHeader() reads the header set earlier by jQuery call. Also, I've amended the method slightly to accept HttpRequestBase.

Tip: To avoid adding ValidateRequestHeader() to every controller that responds to ajax calls, add it to your base controller if you have any, and derive all controllers from the base. Or even better create your own [ValidateAntiForgeryAjaxToken] attribute.

他のヒント

For those had this issue the accepted answer is good but as he mentioned it you should create action filter for cleaner code this is how I do it

create Extention class and method

 public static class ExtentionUtilty
{
    public static string TokenHeaderValue()
    {
        string cookieToken, formToken;
        AntiForgery.GetTokens(null, out cookieToken, out formToken);
        return cookieToken + ":" + formToken;
    }
}

Use it in your cshtml and ajax call

$.ajax("api/values", {
    type: "post",
    contentType: "application/json",
    data: {  }, // JSON data goes here
    dataType: "json",
    headers: {
        'RequestVerificationToken': '@ExtentionUtilty.TokenHeaderValue()'
    } 
});

Create an ActionFilter

public class ValidateHeaderAntiForgeryAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string cookieToken = "";
        string formToken = "";
        if (filterContext.HttpContext.Request.Headers["RequestVerificationToken"] != null)
        {
            string[] tokens = filterContext.HttpContext.Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        }
        try
        {
            AntiForgery.Validate(cookieToken, formToken);
            base.OnActionExecuting(filterContext);
        }
        catch
        {
            filterContext.Result = new HttpNotFoundResult();
        }
    }
}

and simply use it like this:

    [HttpPost]
    [ValidateHeaderAntiForgery]
    [Authorize(Roles = "Admin")]
    public ActionResult ActiveBoomSar(int id, modelDto model){}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top