It's mentioned here, http://www.kendoui.com/forums/ui/upload/rails-anti-forgery-tokens.aspx, that you plan on making forgery tokens work for the next release. Did that happen and does it work in the DataSource? I'm trying to do exactly what is described here http://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken but not sure how I can make that work.
Thanks
Matt
18 Answers, 1 is accepted
I am glad to inform you that this functionality is available in the latest official release. You can download it from your account and give it a try.
Greetings,
Alexander Valchev
the Telerik team
I am sorry for the confusion we created. Are you using Rails or ASP.NET MVC?
If you use the jquery-rails gem, such modification is not needed, and the datasource works out of the box (as it uses jQuery ajax).
If you are using MVC, you could add the token to the request either through the request options:
transport: {
read: {
url: url,
type:
"POST"
,
data: {
__RequestVerificationToken: $(
"input[name=__RequestVerificationToken]"
).val()
}
}
or through the transport parameterMap function. I attached a sample project which implements this scenario. I hope it helps.
Greetings,
Daniel
the Telerik team
There is a workaround for this in ASP MVC which requires extending the anti-forgery token class in MVC. But to avoid having to take apart the json package twice to get this value out, I am trying to send it in the headers instead (and then have my custom anti-forgery class look for it there).
The problem is I don't seem to see the header being submitted when the DataSource does its sync. For example:
update: {
url: 'www.fakeurl.com/blah',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
headers: { 'Forgery-Token':
$(
"input[name=__RequestVerificationToken]"
).val()
}Thanks!
Mike
All I have seen in the docs/examples (if I remember right) is a statement that the transport operations is just a thin wrapper over the jQuery AJAX call. And many of the config properties match verbatim (and are truly just passed thru).
So my question is, is that true for all the allowed $.ajax parameters, including headers? If so, why does my code above not send the declared header? If it is not supported, is there a recommendation for adding a header to these update operations on the transport?
Thanks!
Mike
Yes, all jQuery Ajax parameters can be used in the configuration and at least on my side the headers are send with the request. Is the "Forgery" header sent when using a normal request outside of the DataSource? Also, please check if it is sent when using the beforeSend event to add it e.g.
update: {
url: url,
type:
"POST"
,
dataType:
"json"
,
contentType:
"application/json; charset=utf-8"
,
beforeSend:
function
(xhr) {
xhr.setRequestHeader(
'Forgery-Token'
, $(
"input[name=__RequestVerificationToken]"
).val());
}
}
Regards,
Daniel
the Telerik team
For posterity, I can confirm that both methods work (using headers like I was and your example of using the beforeSend event).
Thank you for confirming all ajax options are supported!
Cheers,
Mike
Adding the token automatically is not planned and a parameterMap function is not available because the requests are made via HTML elements in this mode. It should be possible to pass the token when using server binding by adding it to the route values:
@{
var token = Html.AntiForgeryToken().ToHtmlString();
var tokenValue =
new
System.Text.RegularExpressions.Regex(
"value=\"(.*?)\""
).Match(token).Groups[1].Value;
var routeValues =
new
{ __RequestVerificationToken = tokenValue };
}
@(Html.Kendo().Grid(Model)
.Name(
"grid"
)
.DataSource(dataSource => dataSource
.Server()
.Read(read => read.Action(
"ReadAction"
,
"Controller"
, routeValues))
.Update(update => update.Action(
"UpdateAction"
,
"Controller"
, routeValues))
.Create(create => create.Action(
"CreateAction"
,
"Controller"
, routeValues))
.Destroy(destroy => destroy.Action(
"DestroyAction"
,
"Controller"
, routeValues))
For update and create you could also include the token inside an editor used for the grid.
Regards,
Daniel
Telerik
Hello Matthew,
You shouldn't need to do anything else as long as those routeValues are used in the DataSource configuration.
The grid will send them as part of the request.
Read(read => read.Action(
"ReadAction"
,
"Controller"
, routeValues))
.Update(update => update.Action(
"UpdateAction"
,
"Controller"
, routeValues))
.Create(create => create.Action(
"CreateAction"
,
"Controller"
, routeValues))
.Destroy(destroy => destroy.Action(
"DestroyAction"
,
"Controller"
, routeValues))
What happens when you do that?
Regards,Atanas Korchev
Telerik
.DataSource(dataSource => dataSource
.Server()
.Destroy(x => x.Action(
"Delete"
,
"ControllerName"
, routeValues))
.Model(model => {model.Id(r => r.Id);}))
The delete button posts and adds the request verification token to the route value as expected, but I get the following error: The required anti-forgery form field "__RequestVerificationToken" is not present.
After looking at the resulting HTML I now realize that the anti forgery token must be included withing the <form> that surrounds the delete button for it to work properly. Is there any way to accomplish this?
Thanks!
I had an epiphany of sorts right after making my previous post that I thought I should share. I discovered a way to add an antiforgerytoken to each form within the grid row. Here's the column code:
columns.Command(command => {
command.Destroy().Text(Html.AntiForgeryToken().ToHtmlString() +
"Delete"
);})
This is not a pretty solution, but it does the trick. Also, if you don't want lots of different AntiForgeryTokens running around in your grid here's another method:
@{
string
antiForgeryTokenText = Html.AntiForgeryToken().ToHtmlString();}
// Inside your grid column
columns.Command(command => {
command.Destroy().Text(antiForgeryTokenText +
"Delete"
);
})
This eliminates repeated calls to Html.AntiForgeryToken helper, which I like.
It would be nice if there were another more specialized method besides Text() to do this, perhaps something like this: .FormHiddenValues(new {AdditionalFormValue="some value"}).
I would still like to see some method of automatically adding the antiforgerytoken in the future for both server and ajax bound grids.
Thanks!
Please ensure that you use the server binding configuration for DataSource suggested in the previous posts.
Alternatively, you can pass the additional information via the Data() function of the Read Action as described in the thread below:
Regards,
Viktor Tachev
Telerik by Progress
Thanks Victor, I managed to get this working with .Data().
For anyone else struggling with this, this is how I got it working:
@(Html.Kendo().Grid<TestViewModel>()
.DataSource(dataSource => dataSource
.Ajax()
.Create(cfg => cfg
.Action(
"Create"
,
"Test"
)
.Data(
"getRequestVerificationToken"
)
)
.Update(cfg => cfg
.Action(
"Update"
,
"Test"
)
.Data(
"getRequestVerificationToken"
)
)
)
)
With the javascript function as follows:
function
getRequestVerificationToken() {
return
{
__RequestVerificationToken:
"@(new System.Text.RegularExpressions.Regex("
value=\
"(.*?)\""
).Match(Html.AntiForgeryToken().ToHtmlString()).Groups[1].Value)"
};
}