I am trying to set Register and Login for Hot Towel SPA applicantion. I have created SimpleMembershipFilters and ValidateHttpAntiForgeryTokenAttribute based on the asp.net single page application template.
How do you get the
@Html.AntiForgeryToken()
code to work in the Durandal SPA pattern.
Currently I have a register.html
<section>
<h2 data-bind="text: title"></h2>
<label>Firstname:</label><input data-bind="value: firstName" type="text" />
<label>Lastname:</label><input data-bind="value: lastName" type="text" />
<label>Email:</label><input data-bind="value: emailAddress" type="text" />
<label>Company:</label><input data-bind="value: company" type="text" />
<br />
<label>Password:</label><input data-bind="value: password1" type="password" />
<label>Re-Enter Password:</label><input data-bind="value: password2" type="password" />
<input type="button" value="Register" data-bind="click: registerUser" class="btn" />
</section>
register.js:
define(['services/logger'], function (logger) {
var vm = {
activate: activate,
title: 'Register',
firstName: ko.observable(),
lastName: ko.observable(),
emailAddress: ko.observable(),
company: ko.observable(),
password1: ko.observable(),
password2: ko.observable(),
registerUser: function () {
var d = {
'FirstName': vm.firstName,
'LastName': vm.lastName,
'EmailAddress': vm.emailAddress,
'Company': vm.company,
'Password': vm.password1,
'ConfirmPassword': vm.password2
};
$.ajax({
url: 'Account/JsonRegister',
type: "POST",
data: d ,
success: function (result) {
},
error: function (result) {
}
});
},
};
return vm;
//#region Internal Methods
function activate() {
logger.log('Login Screen Activated', null, 'login', true);
return true;
}
//#endregion
});
In the $ajax call how do I pass the AntiForgeryToken? Also how do I create the token as well?
I struggled a bit with this as neither of the existing answers seemed to work correctly for the case of my Durandal SPA app based on the Hot Towel Template.
I had to use a combination of Evan Larson's and curtisk's answers to get something that worked the way I think its supposed to.
To my index.cshtml page (Durandal supports cshtml alongside html) I added the following just above the
</body>
tagI added a custom filter class as suggested by Evan Larson, however I had to modify it to support looking up the cookie value separately and utilize __RequestVerificationToken as the name rather than RequestVerificationToken as this is what is supplied by AntiForgery.GetHtml();
Subsequently in my App_Start/FilterConfig.cs I added the following
In Application_Start under my Global.asax I added
Finally for my ajax calls I added a derivation of curtisk's input lookup to add a header to my ajax request, in the case a login request.
This causes all of my post requests to require a verification token which is based upon the cookie and hidden form verification tokens created by AntiForgery.GetHtml();
From my understanding this will prevent the potential for cross site scripting attacks as the attacking site would need to be able to supply both the cookie and the hidden form value to be able to verify themselves, which would be far more difficult to acquire.
I would read this article on how to use antiforgery tokens using javascript. The article is written for WebApi but it can easily applied to an MVC controller if you want to.
The short answer is something like this: Inside your cshtml view:
Then inside your asp.net controller you need to validate the token like so:
The reason you want to pass it in the headers is because if you pass it as a parameter data parameter in your ajax call, inside the querystring or body, of the request. Then it will be harder for you to get the antiforgery token for all your different scenarios. Because you will have to deserialize the body and then find the token. In the headers its pretty consistent and easy to retrieve.
****edit for ray**
Here is an example of an action filter which you can use to attribute web api methods to validate if a antiforgerytoken is provided.
If using MVC 5 read this solution!
I tried the above solutions, but they did not work for me, the Action Filter was never reached and I couldn't figure out why. The MVC version is not mentioned above, but I am going to assume it was version 4. I am using version 5 in my project and ended up with the following action filter:
-- Make note of the
using System.Web.Mvc
andusing System.Web.Mvc.Filters
, not thehttp
libraries (I think that is one of the things that changed with MVC v5. --Then just apply the filter
[ValidateJSONAntiForgeryHeader]
to your action (or controller) and it should get called correctly.In my layout page right above
</body>
I have@AntiForgery.GetHtml();
Finally, in my Razor page, I do the ajax call as follows:
Grab value of token in JS var
Then just add to your ajax POST headers in the beforeSend function of the .ajax call