42

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?

Matthew
  • 15,282
  • 27
  • 88
  • 123

5 Answers5

70

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.

Glenn Dayton
  • 1,410
  • 2
  • 20
  • 38
Jens Alm
  • 3,027
  • 4
  • 22
  • 24
  • I actually changed the behaviour a bit. I know create new sessions by sessionCollection.create() and then fire a globally available loginSuccess message that any view can listen to. – Jens Alm May 09 '11 at 20:55
  • Your method sounds great. Any chance you can share a gist of your of the updated code? :) – dbau Apr 26 '12 at 08:13
  • Unfortunately we moved away from this solution to an separate authentication mechanism (cookie-based for now) due to issues on the backend (we wanted to use a ready-made authentication system on the backend) – Jens Alm Apr 26 '12 at 11:58
  • 2
    Would still be worth it sharing a little tutorial or even a fiddle. And of course thank you for explaining this. – montrealist May 24 '12 at 04:34
  • Anyone know how to trigger a DELETE request on logout? window.activeSession.destroy() isn't sending any request for me. – jackocnr Dec 04 '12 at 16:04
  • 1
    I found the solution: you need to give it an ID first, else BB will think it is not yet persisted in the db, and so wont bother sending a DELETE request: window.activeSession.set("id", 0); – jackocnr Dec 04 '12 at 16:16
  • I've been using a global `user` model that changes state from not logged in to guest to registered. It's similar to the session model described above but also includes user profile info. This works pretty well in many cases because the event listening in Backbone is a good fit for this use case. Login/register screens listen to `error`, and any ui element can listen to `sync`. It can have methods on it like `.logOut`. So far the only issues have been around timing/order of operations, but I still think the method is sound. – SimplGy Jun 28 '13 at 21:32
14

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);
       }
     });
  }
});
Kinjal Dixit
  • 7,777
  • 2
  • 59
  • 68
Sam
  • 2,620
  • 2
  • 26
  • 28
  • How would you check before any data is ever received? So that any time the app makes a call for data, it checks to see if they are logged in. if not, it goes to the login page. – Matthew Apr 29 '11 at 14:48
  • 9
    If you want to make the check on every single call to the backend, you should do integrate that with your backend code. E.g., if the user is not authenticated for *any* call, then you can return a `401 Unauthorized` from your backend or something you can catch on the client side. This way, you don't have to make a separate call to check authorization before each data request. In this case you would probably have to override the `Backbone.sync` method to catch that `401 Unauthorized` and emit some event that you can use to detect if a backend call was unauthorized. – Sam Apr 29 '11 at 17:37
5

Here is a very good tutorial for it http://clintberry.com/2012/backbone-js-apps-authentication-tutorial/

Tausif Khan
  • 2,228
  • 9
  • 40
  • 51
2

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.

-14

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

  • 8
    You should do it server side _as well_, but there's nothing wrong with detecting login state on the client provided you don't depend upon it. – Duncan Bayne Dec 29 '11 at 07:10