When i use this function in Cloud Code Parse.User.current() return null.
I'm using parseExpressCookieSession for login.
Any advice?
var express = require('express');
var expressLayouts = require('cloud/express-layouts');
var parseExpressHttpsRedirect = require('parse-express-https-redirect');
var parseExpressCookieSession = require('parse-express-cookie-session');
// Required for initializing enter code hereExpress app in Cloud Code.
var app = express();
// Global app configuration section
app.set('views', 'cloud/views');
app.set('view engine', 'ejs'); // Switch to Jade by replacing ejs with jade here.
app.use(expressLayouts); // Use the layout engine for express
app.set('layout', 'layout');
app.use(parseExpressHttpsRedirect()); // Require user to be on HTTPS.
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('helloworld'));
app.use(parseExpressCookieSession({
fetchUser: true,
cookie: { maxAge: 3600000 * 24 }
}));
Parse.Cloud.beforeSave('Menu', function(request, response) {
var Business = Parse.Object.extend('Business');
var query = new Parse.Query(Business);
query.equalTo('profile', Parse.User.current().get('profile'));
query.find({
success: function(business) {
console.log(business);
response.success();
},
error: function(error) {
response.error(error.message);
}
});
});
app.listen();
This the code that i use to login/logout
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
// Login succeeded, redirect to homepage.
// parseExpressCookieSession will automatically set cookie.
res.redirect('/');
},
function(error) {
// Login failed, redirect back to login form.
res.redirect('/');
});
});
// Logs out the user
app.post('/logout', function(req, res) {
Parse.User.logOut();
res.redirect('/');
});
It is an old question but answering for future reference.
Parse.User.current() works in Javascript SDK when used in clients ex. WebApp where users log in and the you can fetch the current user with that function.
To get the user calling a Cloud Code function or doing an operation on an object (beforeSave,afterSave,beforeDelete and so on) you use the request.user property it contains the user issuing the request to Parse.com.
More details about Parse.Cloud.FunctionRequest here: https://parse.com/docs/js/api/classes/Parse.Cloud.FunctionRequest.html
Example code:
Parse.Cloud.beforeSave('Menu', function(request, response) {
var requestUser = request.user;
// instance of Parse.User object of the user calling .save() on an object of class "Menu"
// code cut for brevity
});
Related
I am migrating an application from parse.com to buddy.com. One of the caveats of the migration was that Parse.User.current() is no longer available on buddy.com, instead you have to get the user and session token from the request itself: https://github.com/ParsePlatform/Parse-Server/wiki/Compatibility-with-Hosted-Parse#no-current-user
The application I am migrating has a logoutUser method that I am attempting to migrate:
Parse.Cloud.define("logoutUser", function(request, response) {
Parse.User.logOut().then(
function onSuccess(result){
response.success(result);
},
function onError(error) {
response.error(error);
}
)
});
now I am attempting to do this in the new style, but am receiving an error. (NOTE: This is cloud code not a nodejs environment)
{
"code":"500",
"error":"Error: There is no current user user on a node.js server environment."
}
New implementation:
function logoutUser(request, response) {
var user = request.user;
var sessionToken = user.getSessionToken();
Parse.User.logOut({ sessionToken }).then(
function onSuccess(result){
response.success(result);
},
function onError(error) {
response.error(error);
}
)
}
Parse.Cloud.define("logoutUser", function(request, response) {
logoutUser(request, response);
});
Suggestions on how to correctly log out users in the Parse on Buddy cloud code?
You could fetch user's session or sessions and delete it / them:
var query = new Parse.Query("_Session");
query.descending('createdAt');
query.equalTo('user', {__type:"Pointer", className:"_User", objectId:"idhere"});
query.first({
useMasterKey: true
}).then(function(session) {
var sessions = [];
sessions.push(session);
Parse.Object.destroyAll(sessions);
}, function (err) {
console.log("Internal error " + err);
});
OR for more tokens you could use find instead of first like:
var query = new Parse.Query("_Session");
query.equalTo('user', {__type:"Pointer", className:"_User", objectId:"idhere"});
query.find({
useMasterKey: true
}).then(function(sessions) {
Parse.Object.destroyAll(sessions);
}, function (err) {
console.log("Internal error " + err);
});
The above will mostly delete or tokens related to the given user. If you wish to delete only tokens used for login, and not for signup or upgrade, then you could put into your query:
query.equalTo('createdWith', { action: 'login', authProvider: 'password'});
As far as i know, deleting a user's last used for login token, then he is logged-out.
To add to the above, if you pass up the user's session key to the Cloud Code function via the X-Parse-Session-Token header, you can use the populated request.user object in the session query directly, instead of the user's ID.
Parse Cloud code:
Parse.Cloud.define("twitter", function(req, res) {
/*
|--------------------------------------------------------------------------
| Login with Twitter
| Note: Make sure "Request email addresses from users" is enabled
| under Permissions tab in your Twitter app. (https://apps.twitter.com)
|--------------------------------------------------------------------------
*/
var requestTokenUrl = 'htt****/oauth/request_token';
var accessTokenUrl = 'http***itter.com/oauth/access_token';
var profileUrl = 'https://api.twitter.com/1.1/account/verify_credentials.json';
// Part 1 of 2: Initial request from Satellizer.
if (!req.params.oauth_token || !req.params.oauth_verifier) {
var requestTokenOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
oauth_callback: req.params.redirectUri
};
// Step 1. Obtain request token for the authorization popup.
request.post({
url: requestTokenUrl,
oauth: requestTokenOauth
}, function(err, response, body) {
var oauthToken = qs.parse(body);
// console.log(body);
// Step 2. Send OAuth token back to open the authorization screen.
console.log(oauthToken);
res.success(oauthToken);
});
} else {
// Part 2 of 2: Second request after Authorize app is clicked.
var accessTokenOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
token: req.params.oauth_token,
verifier: req.params.oauth_verifier
};
// Step 3. Exchange oauth token and oauth verifier for access token.
request.post({
url: accessTokenUrl,
oauth: accessTokenOauth
}, function(err, response, accessToken) {
accessToken = qs.parse(accessToken);
var profileOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
token: accessToken.oauth_token,
token_secret: accessToken.oauth_token_secret,
};
console.log(profileOauth);
// Step 4. Retrieve user's profile information and email address.
request.get({
url: profileUrl,
qs: {
include_email: true
},
oauth: profileOauth,
json: true
}, function(err, response, profile, USER) {
console.log(profile);
//console.log(response.email);
Parse.Cloud.useMasterKey();
var UserPrivateInfo = Parse.Object.extend("UserPrivateInfo");
var query = new Parse.Query(UserPrivateInfo);
query.equalTo("email", profile.email);
query.first({
success: function(privateInfo) {
if (privateInfo) {
res.success(privateInfo.get('user'));
} else {
response.success();
}
},
error: function(error) {
response.error("Error : " + error.code + " : " + error.message);
}
});
});
});
}
});
For client side using Sendgrid twitter authentication:
loginCtrl.twitterLogin = function() {
$auth.authenticate("twitter").then(function(response) {
console.log(response.data.result);
var user = response.data.result;
if (!user.existed()) {
var promise = authFactory.saveUserStreamDetails(user, response.email);
promise.then(function(response) {
signInSuccess(response);
}, function(error) {
console.log("error while saving user details.");
});
} else {
signInSuccess(user);
}
}).catch(function(error) {
console.log(error);
});;
};
Issue:
Step 1: Called cloud function Parse.Cloud.define("twitter", function(req, res) using loginCtrl.twitterLogin
Step 2: Twitter popup opens and user logs in to twitter
Step 3: Got verification keys and again cloud function Parse.Cloud.define("twitter", function(req, res) is called and user is verified
Step 4: Got the user email using the twitter API.
Step 5: I can get the existing Parse User Object using the email or can signUp using that email.
Step 6: Returns the parse user object to client but there is no session attached to it so **How can I create user session?
Without parse session we can not log in to parse application. Every clound code api/ function call will fail as no session is attached to them. So how can I create and manage a session using twitter authentication.
I'm using parse on node. I have an express app, and a JS browser app, that is hosted off the express server.
At the moment the app has it's own login. It logs the user in on the client, and the client remains logged in.
I want to be able to log the client in via an express route /login. When they log in via this route, i want to log them in on the client side.
I have poured over documentation on this but I have struggled to find any real examples of how this is all done.
Here is some code i have found:
var cookieSession = require('cookie-session'),
// I added this require as it seems the code is using it;
session = require('express-session');
app.use(cookieSession({
name: COOKIE_NAME,
secret: "SECRET_SIGNING_KEY",
maxAge: 15724800000
}));
//
// This will add req.user if they are logged in;
//
app.use(function (req, res, next) {
Parse.Cloud.httpRequest({
url: 'http://localhost:1337/parse/users/me',
headers: {
'X-Parse-Application-Id': 'myAppId',
'X-Parse-REST-API-Key': 'myRestAPIKey',
'X-Parse-Session-Token': req.session.token
}
}).then(function (userData) {
req.user = Parse.Object.fromJSON(userData.data);
next();
}).then(null, function () {
return res.redirect('/login');
});
});
//
// login route;
//
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
req.session.user = user;
req.session.token = user.getSessionToken();
res.redirect('/');
}, function(error) {
req.session = null;
res.render('login', { flash: error.message });
});
});
//
// and logout.
//
app.post('/logout', function(req, res) {
req.session = null;
res.redirect('/');
});
This looks pretty good, but this won't add a session on the client? How do parse the server login down to the client; Do i pass the session Token and use it on the client?
//
// If i call this code in the browser, i want the logged in user;
//
var current_user = Parse.User.current();
I have been unable to find any real code on-line that demonstrates all of this in the best-practice manner.
Is this the 'best practice' known solution or is there a better way of doing this?
Below is my parse cloud code. I am unable to get user session even when I am using master key. Is it not possible to get User session even if we use mater key to retrieve user?
Parse.Cloud.define("getFSUserSession", getFSUserSession);
function getFSUserSession(request, response) {
Parse.Cloud.useMasterKey();
//Removed some codes here to make it short
var someID = request.params.user;
var query = new Parse.Query(Parse.User);
query.equalTo('familySearchID', someID);
query.ascending('createdAt');
query.first({useMasterKey: true}).then(function (user) {
console.log(typeof user.getSessionToken());//this returns function
console.log(user.getSessionToken()); //this logs No Message provided
response.success(user.getSessionToken());
})
}
I had to disable Require Revocable Sessions to make this work. After disabling Require Revocable Sessions in settings we can make an api request to /1/upgradeToRevocableSession to get the upgraded session token.
Parse.Cloud.define("getFSUserSession", getFSUserSession);
function getFSUserSession(request, response) {
Parse.Cloud.useMasterKey();
//Removed some codes here to make it short
var someID = request.params.user;
var query = new Parse.Query(Parse.User);
query.equalTo('familySearchID', someID);
query.ascending('createdAt');
query.first({useMasterKey: true}).then(function (user) {
return Parse.Cloud.httpRequest({
method: 'POST',
url: 'https://api.parse.com/1/upgradeToRevocableSession',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': restKey,
'X-Parse-Session-Token': user.getSessionToken()
}
});
}).then(function (httpResponse) {
var sessionObject = httpResponse.data;
if (sessionObject.sessionToken) {
return Parse.Promise.as(sessionObject.sessionToken);
}
return Parse.Promise.error('Unable to get Session token');
});
}
I am using supertest and mocha to test a nodejs application. One of the things users can do is to submit a very simple form, which is picked up by the node server and parsed using formidable.
Here is the mocha test code:
var should = require('should'),
express = require('express'),
app = require('../app.js'),
request = require('supertest'),
csrfToken,
sessionId,
cookies = [];
describe('Post Handler', function(){
it('Uploads new post', function(done){
var req = request(app).post('/post?_csrf=' + csrfToken);
req.cookies = cookies;
req
.type('form')
.send({fieldTitle: 'autopost'})
.send({fieldContent: 'autocontent'})
.send({contentType: 'image/png'})
.send({blobId: 'icon_23943.png'})
.expect(200)
.end(function(error, res){
console.log('here');
done();
});
});
csrfToken retrieves a csrf token from the server, since I am using the csurf module and every POST method requires a csrf token. cookies stores the session cookie that is provided by the node server so I can persist the session between requests.
The form is processed by the following code:
//Takes HTTP form posted by client and creates a new post in the Db
exports.postPostUpload = function (req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
console.log(err);
if (err) res.redirect(303, '/error');
else {
var new_post = new post_model.Post().createNewPost(fields);
new_post.setUserId(req.session.passport.user.userId);
new_post.uploadPostToDb(function (error, result) {
if (error) return res.status(500).end();
else {
if (new_post.media.contentType.indexOf('video') !== -1) {
addMessageToEncodingQueue(new_post, function (error, result, response) {
if (error) {
errorHelper.reportError({
stack: new Error().stack,
error: error
});
res.status(500).end();
}
else res.status(200).send(new_post.cuid);
});
}
else return res.status(200).send(new_post.cuid);
}
});
}
});
}
My current problem is, that once the form handler executes the line form.parse(req, function (err, fields, files) {, nothing happens. Formidable does not return error, it just does not return anything. Consequently, the mocha test never receives a reply from the server, and eventually the socket hangs and the test crashes. Needless to say, the form is successfully submit if you do it manually via the website.
There must be an error in the way supertest/mocha are executing this test, but I have not been able to find it. Any pointers are highly appreciated.