Reputation: 14791
I am developing an ASP.NET MVC Web Application. I am using AngularJS. But I am having a problem with submitting post form to server because of CSRF validation. First of all, I am new to AngularJS.
In AngularJS, I am submitting form like this on button click event
angular.module('loginApp', ['ui.bootstrap', 'blockUI']).controller('loginController', function ($scope) {
$scope.loginFormData = { }
$scope.submitLoginForm = function()
{
$http.post("url", $scope.loginFormData, function (response) {
})
}
});
At server side, I do CSRF validation to form post
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Login(LoginViewModel model)
{
//Do other stuff
}
Here is my form HTML:
@Html.AntiForgeryToken()
<div class="lock-container">
<div class="panel panel-default text-center paper-shadow" data-z="0.5">
<div class="panel-body">
<div class="form-group">
<div class="form-control-material">
<input class="form-control" ng-model="username" type="text" placeholder="Username">
@Html.LabelFor(x => x.UserName)
</div>
</div>
<div class="form-group">
<div class="form-control-material">
<input class="form-control" ng-model="password" type="password" placeholder="Enter Password">
@Html.LabelFor(x=>x.Password)
</div>
</div>
<button ng-click="submitLoginForm()" class="btn btn-primary">Login <i class="fa fa-fw fa-unlock-alt"></i></button>
</div>
</div>
</div>
Actually it is not a form. I am just submitting data with Ajax basically. You noticed @Html.AntiForgeryToken() at the top. When I inspect in browser, I can see like this.
What I want to do is I want to get that token value and send in the $http post like below.
$http.post("url",{ "_RequestVerificationToken": $scope.csrfToken }, function (response) {
})
If I send like above, csrf validation will be successful at the server. How can I achieve it it AngularJS?
Upvotes: 0
Views: 1846
Reputation: 43
In order to csrf validation to be successful at the server, You need to do some modification in your server-side.
you can create a custom filter attribute in your server-side to validate your anti-forgery token.
Create a class and inherited it from ActionFilterAttribute which is provided by System.Web.MVC. Make sure not to use the web API namespaces.
using System;
using System.Web.Helpers;
using System.Web.Mvc;
namespace CustomFilters.Web.Filters
{
public class MVCAntiForgeryTokenValidatorAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.HttpContext.Request.HttpMethod != "GET")
{
var header = filterContext.HttpContext.Request.Headers.Get("_RequestVerificationToken");
var cookieName = AntiForgeryConfig.CookieName; // this also same as the _RequestVerificationToken
var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(cookieName);
var tokenHeader = string.Empty;
if (!string.IsNullOrEmpty(headers))
{
tokenHeader = header;
}
AntiForgery.Validate(tokenCookie != null ? tokenCookie.Value : null, tokenHeader);
}
base.OnActionExecuting(filterContext);
}
}
}
Then you need to modify your method using above created custom attribute
[HttpPost]
[AllowAnonymous]
[MVCAntiForgeryTokenValidator]
public async Task<JsonResult> Login(LoginViewModel model)
{
//Do other stuff
}
Then you are done. when your method got hit by the angularJs service method, before executing the class method. It will validate the anti-forgery token first.
Upvotes: 2
Reputation: 158
Add token to FormData
var formData = new FormData();
formData.append("__RequestVerificationToken", token);
formData.append("UserName", $scope.kullaniciAdi);
formData.append("Password", $scope.sifre);
$http({
method: 'POST',
url: '/Login/Login',
data: formData,
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
Upvotes: 0
Reputation: 1547
You can pass those values in headers instead of the body content. This can be done globally for that module. Refer below links.
angular.module('app')
.run(function ($http) {
$http.defaults.headers.common['X-XSRF-Token'] =
angular.element('input[name="__RequestVerificationToken"]').attr('value');
});
Please refer this link
AngularJS Web Api AntiForgeryToken CSRF
https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
Upvotes: 0