RequestVerificationToken cookie is not being sent in Ajax POST requests - asp.net-mvc

Here is the Ajax code:
var token = $('form input[name="__RequestVerificationToken"]').val();
var data = {};
data.Type = $(e.target).attr('type');
data.__RequestVerificationToken = token;
url = '#Url.Action("MyAction", "MyController")';
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: "html",
success: function (result) {
//do some stuff
},
error: function (err) {
//display error
}
})
In IE 11 Developer tools, during the initial load of the page (GET), I can see that the RequestVerificationToken cookie is being set. Also, the form element for RequestVerificationToken is being populated too. During the Ajax POST, however, the cookie is not part of the request.
Chrome works fine in both places, and during the Ajax POST, the cookie is present. IE 11 works locally (localhost), but this problem arises when IE 11 accesses the application on the server, and this error is returned:
The required anti-forgery cookie "__RequestVerificationToken_L1JldkNvbm5lY3Q1" is not present.
For some reason IE 11 doesn't include the cookie in the Ajax POST when the application is on the server. I can see that it is missing in the Network tab of IE Developer Tools. In the Network tab of Chrome Developer tools, the cookie is present, and the POSt works.
ASP.NET MVC 5

Related

.NET + Angular - IIS Server refreshing localhost tab in chrome when request is made from fire fox

This is bizarre.
I have an angular app served from a .NET MVC project. When I make a request to the backend and complete the response the page refreshes. This only happens in chrome.
Here are the weird variations I've triggered:
1) Serve the app in Chrome, complete request, refreshes page.
2) Serve the app in Chrome, open FF to localhost (so the same page is open in two browsers), trigger the request in FF, request completes. FF does not restart, but the chrome tab does.
3) Serve the app in FF, request does not refresh the page. Open chrome to localhost, make the request from either FF or Chrome, page refreshes.
The .NET route hit just responds with a JsonResult after a file upload. This happens consistently after the completed request hits the subscription. Heres some relevent code:
// component
this.myService.uploadFile(formGroup, this.Id).subscribe(result =>
{
console.log(result);
});
// service
public uploadFile(form: FormGroup, id: number) {
const options = {
reportProgress: true,
};
const file: File = form.get('file').value;
const formData = new FormData();
formData.append('File', file, file.name);
formData.append('Id', id.toString());
const request = new HttpRequest('POST', '/file', formData, options);
return this.http.request(request)
.pipe<HttpEvent<any>>(
map((event) => {
return this.updateProgress(event, form);
}),
last()
);
}
I use this exact same format elsewhere in the app for another file upload component that has different requirements and I dont have any issues.
I only know enough .NET to be dangerous and I'm primarily an SPA developer. If you need some more information about the .NET configuration just ask. I'd really like to track this down.
UPDATE: I found this GitHub issue that describes a similar event only in chrome. I added return false and $event.preventDefault() both to the end of the upload() function (its the one called by the (click) event in the template) and at the end of the subscription scope.
I'm lost.

MVC Web Api not getting called from javascript ajax

I have a Durandal/Hot Towel test app I'm trying to wire up. I have the below ajax call but I'm getting a 404 error.
GET http/.../api/Pizza/GetPizzasByOrderId?%22a8926610-a713-494c-bb15-46f6487a01c7%22 404 (Not Found)
I can manually change the url to:
http/.../api/GetPizzasByOrderId?orderId=a8926610-a713-494c-bb15-46f6487a01c7
It works. But I would like to know why the other call isn't working or more so, why is the ajax messing the parameter up in the URL and not as data like it does with complex objects. I have a get and a save that is working just fine. The get has zero params and the save is passing a complex object in.
C# Web Api Controller:
public class PizzaController : ApiController
{
[HttpGet]
public IEnumerable<Pizza> GetPizzasByOrderId(Guid orderId)
{
return DATA.GetPizzasByOrderId(orderId);
}
}
JAVASCRIPT:
var dataCall = $.ajax(config.getPizzasByOrderIdUrl, {
data: ko.toJSON(orderId),
type: "get",
contentType: "application/json"
});
Should I just change my JavaScript code to the below and be done with it or is there a better way to talk to the Api?
var getPizzasByOrderId = function (orderId) {
return Q.when($.getJSON(config.getPizzasByOrderIdUrl + "?orderId=" + orderId));
};
You could either use the code as you have it in that last code block, or you could pass in an object in place of your orderId as in the code block below. Either way, the difference is that the orderId parameter is being named.
var dataCall = $.ajax({
url: config.getPizzasByOrderIdUrl,
type: "GET",
data: {orderId : orderId},
});
In regard to why $.ajax() works fine for your POST, you can check this out pretty easily by running these two bits of code and viewing the requests that go across the wire. I recommend using google chrome.
Load a page that has jQuery loaded
Open the developer tools and go to the console
Enter the following code snippet
$.ajax("", {
data: {orderId: 123},
type: "get",
contentType: "application/json"
});
Switch to the network tab and click on the one that ends in ?orderId=123
Notice that it does have the data appended as query string parameters
In the snippet above, replace the "get" with "post"
After you hit enter, you should see another request on the network tab of the developer tools.
Notice that when changing nothing but the request type, the data is moved from the query string to the body. As noted in the comments, WebApi will pull from the body of the request and use the model binder to populate the complex object.

Try to post JSON.stringify object to aspnet mvc controller - bad request

I'm trying to post a JS Object stored in a hidden field:
$("#hdnArr").val(JSON.stringify(arr));
<pre>
$.ajax({
url: form.action,
type: 'POST',
data: $(form).serialize(),
success: function (result) {
//
},
error: function (xhr, textStatus, exceptionThrown) {
//
}
});
</pre>
Locally it is working fine, but in a production server (windows 2012 server with IIS 8), it is returng a Bad Request Error. With Firebug I checked that my hidden value is like this:
hdnArr=%5B%7B%22Type%22%3A%22%22%2C%22TypeB%22%3A%22%22%2C%22TypeC%22%3A%22%22%2C%22TypeD%22%3A%22%22%7D%5D
This problem is basically the % character. How can I enable my server to accept this char?
Ok, I could solve this problem just switching the Managed Pipeline from App Pool to Classic Mode.

Rails Devise 401 from Safari Extension

I'm trying to make a simple $.ajax request to a Rails app running locally.
The request works without any issues from the console but when I make the call from the safari extension the app returns a 401 Unauthorized. I'm not sure if I need to create an api token for each user and pass that in the url string to authenticate or if there's a simple reason why devise is not processing the request even though I'm logged in. My guess is that the culprit is the before filter I have on my controller which looks like this:
before_filter: authenticate_user!
But again, I get the 401 when I am signed in to the app. Just for reference, here's the call I'm making from the extension:
$.ajax({
type: 'GET',
url: 'http://localhost:3000/playlists.json?callback=?,
dataType: 'jsonp',
success: function(data) { console.log(data); },
error: function() { console.log('Uh Oh!'); },
jsonp: 'jsonp',
crossdomain: true
});
Any help would be much appreciated.
Ok figured it out. The cookie being set was set to expire after 'session' which basically means that as soon as you navigate away from the page the session is no longer there. Thus the extension did not have access to this extension cookie. The key was to set an expiration date by default on the session cookie which you can do like this in config/initializers/session_store.rb:
YourApp::Application.config.session_store :cookie_store, {
   :key => '_yourapp_session',
   :expire_after => 60*24*60*60
}
You can read more about cookie types here: http://en.wikipedia.org/wiki/HTTP_cookie#Session_cookie

Posting to Yii PHP framework using Backbone.js

I am trying to use Backbone.js models to save to my Yii web application but I am getting a "The CSRF token could not be verified" response even when the model is a serialized form and I use Backbone.sync to set a header.
The model (the form has the CSRF token in it and sends it as a "YII_CSRF_TOKEN" attribute):
var v = new ModelName ($('.formclass').serializeJSON());
JSON serializer:
//form.serializeJSON
(function( $ ){
$.fn.serializeJSON=function() {
var json = {};
jQuery.map($(this).serializeArray(), function(n, i){
json[n['name']] = n['value'];
});
return json;
};
})( jQuery );
The backbone.sync:
Backbone.old_sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
var new_options = _.extend({
beforeSend: function(xhr) {
console.log('backbone sync');
var token = model.get('X_CSRF_TOKEN');
console.log('token ='+token)
if (token) xhr.setRequestHeader('YII_CSRF_TOKEN', token);
}
}, options)
Backbone.old_sync(method, model, new_options);
};
I have also tried setting the header as 'X_CSRF_TOKEN', to no avail.
YII_CSRF_TOKEN is not a header, it is just a form value.
According to this line our request have to contain
a CSRF cookie, it is already set by first, non-XHR page load
the form data value named YII_CSRF_TOKEN
If you send your data with save() you must send cookies and session id in parameters. See here a cached version of this blog post (cuz its offline now): http://webcache.googleusercontent.com/search?q=cache:tML1kmL08ikJ:blog.opperator.com/post/15671431847/backbone-js-sessions-and-authentication+&cd=1&hl=en&ct=clnk
If you're working on localhost, you might need to setup a Virtual Host to be able to perform cookie authentication as stated in this thread:this thread
IE and Chrome does not accept cookies from localhost so that could be the reason

Resources