I need to implement antiforgery validation to my MVC project. However, I am having problems with the server side.
I am using #Html.AntiForgeryToken() to create the token.
Then i get the token value and include it in Ajax request.
// Get token
var cookie = $('input[name=__RequestVerificationToken]').val();
// Ajax request
return $.ajax({
url: url,
type: 'post',
headers: {
'x-system-source': headerValue,
'x-verification-token': cookie //verification token
},
data: ko.toJSON(entity),
contentType: 'application/json',
dataType: 'json'
});
Code below comes from microsoft documentation, however, I am not sure how to implement it. Should I create a custom attribute with the method below and add the attribute to every http request? If so, what would be the best way? Is it possible to create attribute for a controller level? I would also like to avoid repetitive code as much as possible. In addition, is there a way to unit test aniforgery validation feature to make sure that it works as expected.
I am new to the web development, and I would appreciate if you could provide code samples or point me in the right direction. Thanks for your time.
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("x-verification-token", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
Related
I developed a project using ASP.NET MVC that uses session to keep track of users after login. Simply authorization! So I used the below code to use it as attribute in required controllers:
public class GppAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Session["userId"] == null)
return false;
else
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("~/Auth/Login");
}
}
Finally in controller, doing this:
[GppAuthorize]
// GET: Dashboard
public ActionResult Index()
{
return View();
}
So for above, the scenario works fine. Now I am trying to validate each request with a token for authentication (Checks if the request has valid token to work with server-side) and not sure how to do that in ASP.NET MVC 5 as most of the tutorials uses Web Api. I did few R & D and got this for a basic idea to start. Here is the link with an answer:
Authenticate MVC Controller Using Bearer Token and Redirect To The Controller
It looks promising, the questions are: After login,
How can I create the token and pass it in each http request specifically after user login?
Is there anything that I require to do with session or it should be independent of session
anyway?
If the example code with provided link works, how can I make it work for http request with
Ajax call? Say for below code sample:
$.ajax({
type: "POST",
url: "/Dashboard/GetProducts",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (value) {
alert(value);
GetProjectDetails();
},
error: function (ex) {
alert('Failed to retrieve states.' + ex); //Check if authentication failed here
}
});
Will this help me to prevent unauthorized url to access data from the website or web project
that I am working with (Though I know, it'll but is there any way to override and make
unauthorized url calls)?
It's my first time building a web api. I've successfully set up the model view controller and enabled token generation. However, I am stuck on how to pass the access token through the request header. After I have logged in and attempt to view another page, there is nothing in the header in regards to the authorization therefore I receive a 401 error. I've looked at several blogs, forums and articles over the past couple days and cannot come to a conclusion on how this is done. I have my jquery storing the header in a variable, but I am unsure on where that is stored and how to reference it or where to put the reference. I've messed around with setting it in global.asax and some of the config files, also at the top of the controller class. My next thought is to create a web page for each controller and storing the authorization there, even still I don't know how to dynamically place a token that would vary for other users. I feel like there is something very simple that I'm missing. I suppose my question is how do I store my javascript variable in each request header? Here is my javascript for reference:
$("#btnLogin").on('click', function () {
//var data = { Email: $("#loginEmail").val().trim(), Password: $("#textPwd").val().trim(), ConfirmPassword: $("#loginPwd").val().trim() };
$.ajax(
{
url: "/TOKEN",
type: "POST",
data: $.param({ grant_type: 'password', username: $("#loginEmail").val(), password: $("#loginPwd").val() }),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
success: function (resp) {
sessionStorage.setItem('userName', resp.userName);
sessionStorage.setItem('accessToken', resp.access_token);
var authHeaders = {};
authHeaders.Authorization = 'Bearer ' + resp.access_token;
$.ajax({
url: "https://localhost:44327/api/values",
type: "GET",
headers: authHeaders,
success: function (response) {
$("#loginEmail").val(),
$("#loginPwd").val(),
$("#msg").text(response)
}
});
},
error: function () {
$("#msg").text("Authentication failed");
}
})
});
I am trying to create a demo project which uses .Net ASP.Net WebAPI and KnockoutJs as the front end. I have created the controller methods that listen for the /token post, and validates a user, and returns a token. This is done from an Ajax Post from the Knockout View Model.
This code works. However, when I get 200 back (Success) from the webApi, I then redirect to a controller method, decorated with a [Authorize]. And that's where I hit a 401 - not authorised.
Login()
{
var data = {
username : this.login.emailAddress(),
password : this.login.password(),
RememberMe: this.login.rememberMe(),
grant_type: "password"
}
return $.ajax({
type: "POST",
data: data,
dataType: "json",
url: "/token",
contentType: "application/json"
}).done((reply) => {
window.location.href = "/Home/AnotherThing";
});
}
I think the issue is - I get a response back from my /token (login) call, but do nothing with it. I'm not sure what to do with the token. I stupidly thought that OAuth would somehow put the token into my headers, and they would be there magically. I was wrong.
So, I've been looking for an example, and then best I can find is Here
But this means I am going to have a LOT of repeated code, on each view model
Extract:
function ViewModel() {
var self = this;
var tokenKey = 'accessToken';
var RefTokenKey = 'refreshToken';
self.result = ko.observable();
self.user = ko.observable();
self.token = ko.observable();
self.refreshToken = ko.observable();
function showError(jqXHR) {
self.result(jqXHR.status + ': ' + jqXHR.statusText);
}
self.callApi = function () {
self.result('');
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
}
self.callToken = function () {
self.result('');
var loginData = {
grant_type: 'password',
username: self.loginEmail(),
password: self.loginPassword()
};
$.ajax({
type: 'POST',
url: '/Token',
data: loginData
}).done(function (data) {
self.user(data.userName);
// Cache the access token in session storage.
sessionStorage.setItem(tokenKey, data.access_token);
var tkn = sessionStorage.getItem(tokenKey);
$("#tknKey").val(tkn);
}).fail(showError);
}
}
var app = new ViewModel();
ko.applyBindings(app);
This seems to be part of what I am missing:
sessionStorage.setItem(tokenKey, data.access_token);
var tkn = sessionStorage.getItem(tokenKey);
$("#tknKey").val(tkn);
Would I need every view model to have the code that then goes to the sessionStorage, and get the token?
So, this:
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
}
It seems like a lot of code.. Is this the right way to go?
Ok, so what you could do is attach the bearer token to each of your HTTP requests. I assume you're using jQuery there? If that's the case you could leverage the beforeSend config param.
Extract a reusable method such as this:
function onBeforeSend(xhr, settings) {
var token = sessionStorage.getItem(tokenKey);
if (token) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token );
}
}
And then simply attach that method to each of your $.ajax calls that require the token, like this:
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers,
beforeSend: onBeforeSend
}).done(function (data) {
self.result(data);
}).fail(showError);
The onBeforeSend function obviously needs to be accessible by your ajax call (I'm not a knockout guy so I don't know if it has any constructs such as services, but if not, you could namespace it for example to avoid making it a global function, but your code organization is up to you).
This way you'll only have to add the beforeSend: onBeforeSend bit to each request that requires auth and it will avoid unnecessary code duplication.
Is there a way how can I can get request origin value in the api controller when I'm calling some api endpoint with ajax call?
For example I'm making this call from www.xyz.com:
$http({
url: 'http://myazurewebsite.azurewebsites.net/api/ValueCall/CheckForExistingValuers',
method: "GET",
params: { loanID: $scope.loanIdPopup }
}).success(function (data) {
}).error(function (data) {
});
Once on the api side, how can I get the www.xyz.com value?
CORS is working properly.
What you're looking for is probably the origin-header. All modern browsers send it along if you're doing a cross domain request.
In an ApiController you fetch it like so:
if (Request.Headers.Contains("Origin"))
{
var values = Request.Headers.GetValues("Origin");
// Do stuff with the values... probably .FirstOrDefault()
}
You can grab it from the API methods via current HTTP request headers collection:
IEnumerable<string> originValues;
Request.Headers.TryGetValue("Origin", out originValues)
var originValue = Request.Headers["Origin"].FirstOrDefault();
// or
StringValues originValues;
Request.Headers.TryGetValue("Origin", out originValues);
I need to submit a simple form and validate the model. If the model is valid, I would like to serialize that model and send it via POST to an external (https) web service using custom headers. Finally I would handle the response that I get back from the request and display the appropriate message.
I am validating the model from the controller perfectly and serialize the object but can't seem to find a way to create a JSON post request to the external URI. Is there a way to do this using JQuery.ajax or $.post. Maybe I am missing a key ajax param to achieve this.
Thanks
So based on the clarification on the question this is what you can do:
Define the controller method that will validate the object
public ActionResult TestMethod() {
// do server-side validation
return Json(aValidObject);
}
You do an ajax post to your controller so you can validate your model then get back a json result.
$.ajax({
url: '#Url.Action("TestMethod")',
data: some_data,
type: "post",
success: function (result) {
// result is a valid json object
doExternalPost(result);
}
});
Add custom header and do the external post
function doExternalPost(o) {
$.ajax({
url: 'http://some_external_url',
data: o,
dataType: 'json',
beforeSend: function (xhr) {
xhr.setRequestHeader('custom_header', 'some_value');
},
success: function() {
// post is sucessful
},
error: function (xhr, errorType, exception) {
var errorMessage = exception || xhr.statusText || xhr.responseText;
alert('An error has occured: ' + errorMessage);
},
});
}
try this
var data = {jsonDataObjectHere};
var request = $.ajax({
url : 'externalUrl.com/something.whatever',
type : 'POST',
data : data // see above
});
request.success(function(response){
// the response is the stuff from the server
});
i'm sleepy so forgive typos
good luck
EDIT: for a bit of clarification, with MVC you really dont need to serialize the json object, mvc will accept it as it is.