Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to enforce user/authentication state in Ember.JS app

Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).

I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).

What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?

Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.

Edit: I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.

Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.

Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751

like image 774
Conrad Vanlandingham Avatar asked Sep 05 '12 00:09

Conrad Vanlandingham


3 Answers

If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:

By default, the router will begin trying to translate the current URL into application state once the browser emits the DOMContentReady event. If you need to defer routing, you can call the application's deferReadiness() method. Once routing can begin, call the advanceReadiness() method.

Note that at the time of writing this function is available only in ember-latest

like image 143
tokarev Avatar answered Nov 09 '22 02:11

tokarev


In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:

var redirectToLogin = function(router){
    // Do your login check here.
    if (!App.loggedIn) {
        Ember.run.next(this, function(){
            if (router.currentState.name != "login") {
                router.transitionTo('root.login');
            }
        })
    }
};

// Define the routes.
App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
        enter: redirectToLogin,
        login: Ember.Route.Extend({
            route: 'login',
            exit: redirectToLogin,
            connectOutlets: function(router){
                router.get('applicationController').connectOutlet('login');
            }
        }),
        ....
    })
});

The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.

Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:

App.AuthenticatedRoute = Ember.Route.extend({
    enter: redirectToLogin
});
App.Router = Ember.Router.extend({
    root: Ember.Route.extend({
        index: App.AuthenticatedRoute.extend({
            ...
        })
    })
});

If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.

like image 33
Pascal Zajac Avatar answered Nov 09 '22 03:11

Pascal Zajac


I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session

like image 2
andrewreedy Avatar answered Nov 09 '22 02:11

andrewreedy