On a website I'm developing, using Node, Express, and Backbone, I have the user login using a regular HTML form that, when successfully logged in, creates a user session. Accessing this session info is easy on the server-side, giving me access to the User ID, Username, etc., but I'm not sure on how to access this information in Backbone.
I want to acquire the UserID such that I can create a URL for a Collection like this:
url: '/api/users/'+ this.userID +'/movies';
But I'm not sure how to best go about acquiring the userID based upon the Session data that's on the server-side. Would this require creating another model -- say, a 'User' model that fetches the session data from the server, through a particular url/get request?
Thanks!
I came up with something, but would still be open to suggestions:
First, create a function in Express.js that returns the userId:
app.get('/api/current-user', middleware.requiresLogin, function(req, res){
res.send(req.session.user._id);
});
Second, on the client side, retrieve the ID using either a Backbone model or $.get request:
var userID = $.get("/api/current-user");
$.when(userID).then(function(data){
var user = new userCollection(data);
user.fetch();
});
With your collection and model doing this:
window.userModel = Backbone.Model.extend({
idAttribute: "_id"
});
var userCollection = Backbone.Collection.extend({
model: userModel,
initialize: function(options){
this.url = "/api/users/"+options+"/movies";
this.model.urlRoot = "/api/users/"+options+"/movies";
}
});
myModel.save(); then works correctly.
Related
this maybe simple but I can't find an answer on the web. My Ember app is using the Ds.store.find method to find a user in the store and the backend database if not in the store. I'm using Firebase for the backend database and their EmberFire adapter. When the database do not find the record, the find method crash with the following message in the Google debug tool:
"Error while processing route: user.index No model was found for 'user' Error: No model was found for 'user'"
How can I handle this error before and have instead a alert showing to the user that they need to login?
The UserRoute code is:
App.UserRoute = Ember.Route.extend({
model: function() {
var _authUID = this.get('firebase').authUID
return this.store.find('user', _authUID);
},
});
Thanks in advance!
The error you are seeing actually doesn't mean that the user isn't being found, it means that you have not defined a user model in ember-data.
You need to define a model like this:
App.User = DS.Model.extend({
// Model attributes
});
I'm currently writing a server-centric package for Meteor, and the relevant code looks something like this:
__meteor_bootstrap__.app.stack.unshift({
route: route_final,
handle: function (req,res, next) {
res.writeHead(200, {'Content-Type': 'text/json'});
res.end("Print current user here");
return;
}.future ()
});
This is obviously a relatively hacky way of doing things, but I need to create a RESTful API.
How can I access Meteor.userId() from here? The docs say it can only be accessed from inside a method or publish. Is there any way around that?
Things I've tried:
Capture it from a publish using Meteor.publish("user", function() { user = this.userId() });
Get the token + user id from the cookies and authenticate it myself using something like Meteor.users.findOne({_id:userId,"services.resume.loginTokens.token":logintoken});
Create a method called get_user_id and call it from inside my code below.
The thing that you need to target first is that to get something that can identify the user from headers (especially because you want to get the username at a point where no javascript can run).
Meteor stores session data for logins in localStorage, which can only be accessed via javascript. So it can't check who is logged in until the page has loaded and the headers have been passed.
To do this you need to also store the user data as a cookie as well as on localStorage:
client side js - using cookie setCookie and getCookie functions from w3schools.com
Deps.autorun(function() {
if(Accounts.loginServicesConfigured() && Meteor.userId()) {
setCookie("meteor_userid",Meteor.userId(),30);
setCookie("meteor_logintoken",localStorage.getItem("Meteor.loginToken"),30);
}
});
server side route
handle: function (req,res, next) {
//Parse cookies using get_cookies function from : http://stackoverflow.com/questions/3393854/get-and-set-a-single-cookie-with-node-js-http-server
var userId = get_cookies(req)['meteor_usserid'];
var loginToken = get_cookies(req)['meteor_logintoken'];
var user = Meteor.users.findOne({_id:userId, "services.resume.loginTokens.token":loginToken});
var loggedInUser = (user)?user.username : "Not logged in";
res.writeHead(200, {'Content-Type': 'text/json'});
res.end("Print current user here - " + loggedInUser)
return;
}.future ()
The cookie allows the server to check who is logged in before the page is rendered. It is set as soon as the user is logged in, reactively using Deps.autorun
My solution was inspired by the server part of #Akshat's method. Since I'm making a RESTful API, I just pass the userId/loginToken in every time (either as a param, cookie or header).
For anyone interested, I bundled it as a package: https://github.com/gkoberger/meteor-reststop
I have the following functionality at my API and I strumbled upon a few questions:
POST /user (requires fullName, email, password) will create a new user, if the user has been created an unique activation ID is generated and a link to activate the account is send through mail to the user.
PUT /user (requires id, email) will activate the user.
Once the user has activated it's account, it can login.
POST /session (requires email, password) and logs in the user.
GET /session will look at the cookie session id and return user info if auth.
DELETE /session logs the user out.
Once the user is logged in, he is asked to submit their interests (just a HTML textarea) and they can submit a description about their account too (Location, gender, etc but it is all optional so also an HTML textarea just like Twitter account description)
Now my question is:
As you can see 2. PUT /user will activate the user, but how would I handle the submit interests and account description in a proper restful design?
Should I look at the point where at my backend server PUT /user will come in and detect the fields that where submitted?
Or would it make more sence to create a separated PUT /user/activate and PUT /user/interests.
Once this is finished, I want to expand it with restore password, also this would be a PUT /user wouldn't the field detection at the server side will get kinda messy?
Now about backbone, this is my session model:
var Session = Backbone.Model.extend({
url: '/session'
});
var session = new Session();
session.fetch(); // Get the user authentication of the backend server.
my user model:
var User = Backbone.Model.extend({
url: '/user'
});
function signup(fullName, email, password){
var user = new User();
user.save({
fullName: fullName,
email: email,
password: password
});
};
function activate(id, activationId){
var user = new User();
user.save({
id: id,
activationId: activationId
});
};
// Possibility...?
function submitInterests(id, interests){
var user = new User(url: '/user/interests/');
user.save({
id: id,
activationid: activationId
});
}
Thank you for reading.
A rule of thumb in RESTful world is:
Verbs down, nouns up.
That's because the magic 4 [GET, POST, PUT, DELETE] should be enough for all actions: no /users/activate / /user/edit stuff around.
While making a PUT over the whole /users for activation may seem legit, so would be making all the requests to /root and passing "entity = users, id = 3, ..." and so on.
I advice you to use /entityname for the collection [where you can POST to create a new one], then /entityname/:id in order to refer to a single entity [in this case, a single user].
Now you can make a PUT on /users/123 to accomplish whatever you need.
Of course you can nest resources:
/users/:id/interests
This is the route for all interests of :id-th user - you can issue a GET over it to retrieve them all, or a POST to add an element to the list, a PUT to set all the list from scratch.
One last thought about your session resource: a true RESTful service should be *stateless, i.e. it should not rely on session. Authorization has to be made on every request, see HTTP Basic Auth, though you can come with a session sometimes.
To be consistent to your schema, you can define a /user/:id/sessions resource where you can POST in order to make a new login, so you can keep track of user accesses.
I'm creating an ST2 application where you can login/register etc.
I'm wondering what the normal way is of logging in and having the User state across the entire application.
I have a User model with a REST proxy to get/save the data. When you load up the application I'm doing this to grab the user:
launch: function () {
var User = Ext.ModelManager.getModel('App.model.User');
User.load("", {
success: function (user) {
// I have the user here but it's only within this scope
}
});
}
But doing this it's only available within this function... so what do people usually do to get ahold of the user across the whole application? just store it within the application like:
application.user = user;
or do you create a store with an ID of User, using the User model and then retrieve with:
launch: function () {
var User = Ext.StoreManager.get('User');
User.load(function(user) {
// Do application logged in stuff
self.getApplication().fireEvent('userLogsIn');
});
}
someRandomFunction: function () {
var user = Ext.StoreManager.get('User').getAt(0),
email = user.get('email');
console.log(email);
}
Thanks, Dominic
Generally speaking you cannot rely on any information you save locally in your JS application. It can be spoofed and altered relatively easy.
What you need to do is to send username/password combination to your server back end. Server then should return encrypted cookie which application will send back to the server with each following request. Only by decrypting and verifying this cookie server can be sure of identity of logged in user.
Firstly, should the static page that is served for the app be the login page?
Secondly, my server side code is fine (it won't give any data that the user shouldn't be able to see). But how do I make my app know that if the user is not logged in, to go back to a login form?
I use the session concept to control user login state.
I have a SessionModel and SessionCollection like this:
SessionModel = Backbone.Model.extend({
defaults: {
sessionId: "",
userName: "",
password: "",
userId: ""
},
isAuthorized: function(){
return Boolean(this.get("sessionId"));
}
});
On app start, I initialize a globally available variable, activeSession. At start this session is unauthorized and any views binding to this model instance can render accordingly. On login attempt, I first logout by invalidating the session.
logout = function(){
window.activeSession.id = "";
window.activeSession.clear();
}
This will trigger any views that listen to the activeSession and will put my mainView into login mode where it will put up a login prompt. I then get the userName and password from the user and set them on the activeSession like this:
login = function(userName, password){
window.activeSession.set(
{
userName: userName,
password: password
},{
silent:true
}
);
window.activeSession.save();
}
This will trigger an update to the server through backbone.sync. On the server, I have the session resource POST action setup so that it checks the userName and password. If valid, it fills out the user details on the session, sets a unique session id and removes the password and then sends back the result.
My backbone.sync is then setup to add the sessionId of window.activeSession to any outgoing request to the server. If the session Id is invalid on the server, it sends back an HTTP 401, which triggers a logout(), leading to the showing of the login prompt.
We're not quite done implementing this yet, so there may be errors in the logic, but basically, this is how we approach it. Also, the above code is not our actual code, as it contains a little more handling logic, but it's the gist of it.
I have a backend call that my client-side code that my static page (index.php) makes to check whether the current user is logged in. Let's say you have a backend call at api/auth/logged_in which returns HTTP status code 200 if the user is logged in or 400 otherwise (using cookie-based sessions):
appController.checkUser(function(isLoggedIn){
if(!isLoggedIn) {
window.location.hash = "login";
}
Backbone.history.start();
});
...
window.AppController = Backbone.Controller.extend({
checkUser: function(callback) {
var that = this;
$.ajax("api/auth/logged_in", {
type: "GET",
dataType: "json",
success: function() {
return callback(true);
},
error: function() {
return callback(false);
}
});
}
});
Here is a very good tutorial for it http://clintberry.com/2012/backbone-js-apps-authentication-tutorial/
I think you should not only control the html display but also control the display data. Because user can use firefox to change your javascript code.
For detail, you should give user a token after he log in and every time he or she visit your component in page such as data grid or tree or something like that, the page must fetch these data (maybe in json) from your webservice, and the webservice will check this token, if the token is incorrect or past due you shouldn't give user data instead you should give a error message. So that user can't crack your security even if he or she use firebug to change js code.
That might be help to you.
I think you should do this server sided only... There are many chances of getting it hacked unit and unless you have some sort of amazing api responding to it