I'm using angularjs to create a simple SPA which allows users to interact with a Bookings list in Hosted SharePoint 2013.
I've got the HTTP GET working fine and retrieving bookings for various filtered queries.
However, now I want to Insert and Update records into the list, but Fiddler shows an 'HTTP Error 403' occurred and the following under JSON tab:
value=The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again.
I would appreciate some help confirming the following code should work. A Submit button on new booking form triggers the post:
$scope.submitForm = function () {
//new booking
if ($scope.editableBooking.Id == 0) {
service.insertBooking($scope.editableBooking, function (data) {
$scope.editableBooking = data;
});
}
// Update booking
else {
console.log("[submitForm] Update");
service.updateBooking($scope.editableBooking, function (data) {
$scope.editableBooking = data;
console.log('[updatedBooking] id = ' + $scope.editableBooking.Id)
});
}
}
Within my factory I have a service to insert booking:
var insertBooking = function (newBooking, callback) {
console.log('[insertBooking] Id = ' + newBooking.Id + " Storeno = " + newBooking.Storeno);
$http({
method: 'POST',
url: "/_api/web/lists/GetByTitle('Bookings')",
data: $.param({
Title: newBooking.Storeno,
Description: newBooking.Description,
BookedBy: newBooking.Bookedby,
StartDate: newBooking.StartDate
}),
headers: { 'Accept': 'application/json; odata=verbose' }
}).success(function (data) {
console.log("[insertBooking] POST worked");
console.log('[insertbooking] New Id = ' + data.Id);
callback(data);
}).error(function (er) {
console.log('[insertBooking] Error = ' + er);
});
}
Searching StackOverFlow is this post on Error 403 which talks about the AppManifest. I don't have access to this file - it's on a corporate intranet - and I haven't built an installable app, just angularjs files called via a CEWP.
Any suggestions please on how to update a SP list?
I've had this same error in the past
The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again.
I found this blog by Wictor Wilén that explains how to refresh the digest token.
Basically you insert this line before your $http invocation:
UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);
Some main points from the blog:
This method is synchronous, so there's no need to worry about callbacks etc.
it uses an update interval and only updates the form digest when needed – so if your digest hasn't expired, there are no additional calls to SharePoint
Related
recently i am working hard on my website with angularjs on the Front End and Symfony 3 on the backend. I put a security layer on my backend so every request from my FE must need a valid token (using grant_type=client_credentials). I have read a looooot about the best practices about call my API Backend with angular... I normally send the token on every request that i make to the Backend, but i read that i can use the $http interceptor to send always on the header my bearer token.
So, i am a little confused that how start... because for one part:
i want to do calls to my backend to load certain data to be used on my pages to show info (using the grant_type=client_credentials) and,
i will have an user management system too. So this users must to login with user and password (again another call to my backend) but with grant_type=password...
The really big question is:
can i do the same things with one interceptor? (one for show page elements data with grant_type=client_credentials and other for the normal users?)
Tha another question is... can i make a token with this interceptor if the token has not been created yet (only for the pages info, for the users i want to refresh the token if is going to expire)?
Sorry if is a little confused... i am confused, i really read many posts, documentation and help... but i don't know where to start... I hope that you can help me...
Thanks for all.
The beauty of JWT is that they are essentially just javascript objects. You could for instance provide the user a token containing their role in the system (user, admin, support etc...) and show/hide elements accordingly.
So basically not only you grant the user access to the API, you also provide them with their type of access. Of course you should NEVER rely on client side authentication to allow restricted API's directly (verify the token on each request, check for the provided role on the server).
Here's an example in NodeJS and Angular:
//In NodeJS...
app.get('/path/to/secured/api', verifyTokenOr401, function(req, res) {
//Do stuff...
res.json({msg: 'Success');
});
function verifyTokenOr401(req, res, next) {
var authHeader = req.headers.authorization;
try {
var token = authHeader.split(' ')[1];
if(jwt.verify(token, 'myAppSecret'))
next();
} catch(e) {
res.status(401).send('Not authorized');
}
}
//Assuming you use node-jsonwebtoken package
app.post('/path/to/authentication', function (req, res) {
//Verify authentication...
User.findOne({username: req.body.username}).then(function(user) {
//VerifyPassword
if(!user)
return res.status(401).send('No such user ' + req.body.username);
if(!user.verifyPassword(req.body.password))
return res.status(401).send('Wrong password for user ' + user.username);
//Provide the user with the access token
var token = jwt.sign({ subject: user.id, role: user.role }, 'myAppSecret');
res.setHeader('Authorization', 'Bearer ' + token.toString());
res.json(user);
})
.catch(function (e) { res.status(500).json(e); });
});
//In angular...
.factory('jwtInterceptor', function() {
return {
request: function(config){
var authHeader = config.headers('authorization');
//Attach header if not present
if(!authHeader)
config.headers.authorization = 'Bearer ' + localStorage.get('myAppToken');
return config;
},
response: function(response){
//Look for token in the header if you get a response and save it
var authHeader = response.headers('authorization');
if(authHeader){
try { localStorage.myAppToken = authHeader.split(' ')[1]; } catch(e) {}
}
return response;
}
}
});
Notable mention: check out auth0's repos for NodeJS and Angular. Both are awesome.
You can create a service which when loaded by angular make a get call for authorization token and set in header. Through this you do not need to set token at every Ajax call. You can do it like this:
app.service("MyService", ["$http", function($http) {
initialize();
function initialize() {
getAuthorizationToken().then(function(response) {
$http.defaults.headers.common.Authorization = 'Bearer some_auth_code_here';
});
}
function getAuthorizationToken() {
// Get call for token
}
}]);
I'm currently developing a Web Application with AngularJS and I have the following question with the login system: is secure to store the information like username you used to login into the cookies?
I mean, when i login I want to store the username or the id, would be the same, into a cookie, so I can load more information from the database each time the user navigates between the different links. The thing is that I don't know if Angular has any protection about cookie edition or, in other words, should I trust this cookie's value will be the correct one?
For example, having this piece of code, is it secure?
var request = {
url: 'backend/getCharacters.php?user=' + $cookies.get('username'),
method: 'GET'
};
$http(request).then(function(response) {
if(response.status == 200)
// Get character list
else
alert('Something went wrong.');
});
You should declare ngCookies in your function. You can see following example to understand more about use cookies in angularjs. I hope you would like these resources.
Use this code. I hope it will be work for you.
angular.module('myApp', ['ngCookies']);
function CookieCtrl($scope, $cookieStore) {
var tabname = [{'KaluSingh'}]; // tabname contains username
$cookieStore.put('username', tabName);
};
var request = {
url: 'backend/getCharacters.php?user=' + $cookies.get('username'),
method: 'GET'
};
$http(request).then(function(response) {
if(response.status == 200)
// Get character list
else
alert('Something went wrong.');
});
stackoverflow.com/questions/10961963/how-to-access-cookies-in-angularjs
https://docs.angularjs.org/api/ngCookies/service/$cookies
https://docs.angularjs.org/api/ngCookies
I am trying to update an existing document in mongodb with node.js. But it does not seem to work. It do not even display the request call in the console. Please suggest what mistake I am doing or how I can I do the update operation in node.js with mongodb. Here is the code:
Node.js Code:
app.put('/addIssueId', function(req, res) {
console.log("Adding issue id")
console.log(req.body.issueKey)
impactMapFeature.update( {productName:req.params.productName, actor:req.body.actor, activity:req.body.activity,feature:req.body.feature},{issueKey:req.body.issueKey}, function ( err, data ) {
console.log("Updating" + data)
});
});
Angular Controller code:
var data = {
productName: $scope.productName,
actor: actor,
activity: impact,
feature : $('#feature').val(),
issueKey : data.key
};
$http.put('/addIssueId', data)
.success(function(data){
}).error(function(data){
console.log('Error in adding issueId' + data)
});
}
As chridam said, you are using req.params which is a route parameter. Either use the following route : /addIssueId/:productName or pass your variable with a query parameter : /addIssueId?productName=productName and {productName = req.query.productName, ... }, or pass your variable as you are doing it in the body (then you just need to change req.params.productName to req.body.productName
WORK AROUND IS AT THE BOTTOM
Original problem
There are question like this all over the web and none of them really have answer for me. I can't get an http PATCH operation to work using angular to save my life. I've implemented $http, with shortcut $http.patch and without using the config object method:PATCH. I've used $resource by adding a custom method. And I've implemented Restangular using their patch and I'm getting the same error. I have the correct Content-Type as suggested in other posts. I think it's safe to say at this point, it's something I'm missing. I'm getting the same "404" message via postman when trying to patch. I can PUT, GET, POST, and DELETE, but not PATCH.
In the following images you can see that the resource exists for GET. But when trying to patch I get 404. Browsing to that endpoint shows the record. Which is stored in Mongodb.
Here's some code snippets:
Resangular GET:
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.get().then(function(res) {
console.log(res)
}, function(err) {
console.log('Restangular failed: ', err)
});
Restangular Patch:
var data = {
corporiumId: $scope.newBlock
};
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.patch(data).then(function(res) {
console.log(res)
}, function(err) {
console.log('Restangular failed: ', err)
});
$http attempt using config object:
controller code:
httpCorporiumSrv.updateCorporiumId('/corporium-mgmnts/' + $scope.params.id, data)
.then(handleUpdateSuccess)
.catch(handleUpdateError);
service code, tried forcing the content-type header but got same result
with or without it:
function updateCorporiumId(url, data) {
return $http({
method: 'PATCH',
url: url,
data: angular.toJson(data),
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
//transformRequest: transformUpdateData
})
.then(handleUpdateSuccess)
.catch(handleUpdateErrors);
}
Using the .patch shortcut:
function updateCorporiumId(url, data) {
return $http.patch(url, data, {
transformRequest: transformUpdateData
})
.then(handleUpdateSuccess)
.catch(handleUpdateErrors);
}
Thing is I've tried this every which way I know how. I don't even know how to start debugging any more. I'm just getting 404 on a resource that does exist. Any suggestions on what might be happening to my request would be great.
Resolution:
For anyone having this issue, if you could post the fix or what's going on here to this point or PM me that would be awesome I'd like to know. I ended up just using PUT to fix this.
Quick Restangular solution:
Build the url template for findByOne like function using Restangular.one(url, _id) where '_id', is the id of the resource you're looking for. .get() goes out and finds that one resource by said id, which you can populate dynamically however you like. Once you have the one resource with GET copy it with Restangular.copy() which is different from angular.copy as it doesn't bind 'this' to the new object. Change what needs to be changed or added in the new object and then perform a .put() on it.
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.get().then(function(res) {
var update = Restangular.copy(res);
// update date corporiumId
update.corporiumId = $scope.newBlock;
// submit new doc with altered value
update.put().then(function() {
console.log('updated')
});
console.log(update)
}, function(err) {
console.log('Restangular failed: ', err)
});
Also because mongo uses _id and Restangular uses id you have to add this to your module
angular.module('corporium-mgmnts').config(function(RestangularProvider) {
RestangularProvider.setMethodOverriders(['put', 'patch']);
// setRestangularFields is required for mongodb
RestangularProvider.setRestangularFields({
id: "_id"
});
});
I'm building a shopping cart with Backbone and I'm having a hard time determining how to structure the interaction with the server. When the user hits the checkout (and after the validation) I need to:
Save the Order using order.save() - Because the order was created on the client this will hit the route on the server and give me back an ID. I need the ID before I process the order.
On success I call a custom method on the Order which hits the server again which does a request to the card processing service.
I either report the err to the client and let him modify and retry or I update the order record and create a Payment record in the database.
Here is my processOrder method in the Order Model:
processOrder: function() {
var order = this.toJSON();
$.ajax({
url: '/api/order/process',
type: 'POST',
data: order,
dataType: 'json',
success: function(res) {
console.log(res);
},
error: function(err) {
//show error message
console.log('error: ' + JSON.stringify(err));
}
});
}
This is where the form is submitted in my view
saveOrder: function() {
...
var order = this.order;
order.set(this.frmJSON);
order.save(this.frmJSON, {
success: function(res) {
console.log('order saved...');
order.processOrder();
},
error: function(err) {
console.log(JSON.stringify(err));
}
});
}
The order is saved on the server and the Order gets an ID inserted into it. When I call processOrder it works until it gets to the ajax call. It never hits the server and the browser hangs up with no error. Is there a better way to structure these steps?