37

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

  • There is an example implementation of authentication states in [this fiddle](http://jsfiddle.net/brundage/dYEJe/). – buuda Sep 05 '12 at 04:24
  • Yeah I remember seeing this but I never looked too much into the source code because the example doesn't seem to do much besides flash "Logged In/Logged out" when you click the login button...try unauthorized doesn't do anything. Looking at the source it looks like logging in is supposed to list news but never does. I'll look more into the source code and see if I can make use of this example. – Conrad Vanlandingham Sep 05 '12 at 05:11
  • Maybe you can create a base controller that does a check that for you, and have your current controllers `extend` it with that functionality already built-in. Similarly you can have a base view (with a binding to some sort of "is authenticated" property) which you'll `extend` to your current views, so you can change the template to "you must authenticate" type of thing if the user isn't authenticated. And as for REST, you might want to implement an API token to provide the client app once the user is authenticated in the server, and for every request that token is sent and verified for real – MilkyWayJoe Sep 05 '12 at 21:56
  • @MilkyWayJoe I thought about that. But when I call connectOutlets in a route the model call is made before the controller is initiated. In my case, I'm sending an API token with each model call, no token = bad request. I guess I could put it in the models, but it just seems rather late to be checking for a logged in user – Conrad Vanlandingham Sep 07 '12 at 07:01
  • I have the same issue I need to solve. Beyond the above solution, I was thinking to implement a authentication which is basically independent from the Ember App itself [not entirely -- this is why it is still a plan]. I have used before the HTML5 Server-Sent Events like this: http://boxed.hu/articles/html5-server-sent-events/ and was planning to use to handle user authentication state. I haven't given it too much time so far, but I will do some kind of testing around it. – Eduárd Moldován Sep 17 '12 at 10:14
  • 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. Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff, let me know if you want to see anything I took out https://gist.github.com/3741751 – Conrad Vanlandingham Sep 18 '12 at 07:19
  • Also, the app I'm building this for supports some things such as multiple logins, which is why the user stack is an array... – Conrad Vanlandingham Sep 18 '12 at 07:21
  • Honestly, I have not fully understood how it actually works in the background, but github.com/simplabs/ember-simple-auth does a really great job for me! – Preexo Jul 15 '14 at 03:04

4 Answers4

8

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

tokarev
  • 2,575
  • 1
  • 21
  • 26
  • Hm. That's good to know. Is this function called every time the state transitions, or only when the page is initially loaded? I'm currently using an edge build of ember-data, which isn't quite compatible with ember-latest, yet. So I'll have to try this out in the future. – Conrad Vanlandingham Oct 10 '12 at 03:29
  • 2
    Only when the page is initially loaded. IMO, it's too much work to check for authentication on every state transition. In our app we do the following - at the initialization we check whether or not a user is authenticated, then we establish a persistent connection to the server. The presence of this connection is what tells us that a user is authenticated. If, for some reason, connection terminates, then the connection manager transitions our app to the guest mode. – tokarev Oct 10 '12 at 04:21
  • 1
    @tokarev How did you implement the persistent connection? – Eduárd Moldován Nov 04 '12 at 16:29
  • 1
    @EduárdMoldován, websockets, long-polling, etc – tokarev Nov 05 '12 at 06:13
3

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.

Pascal Zajac
  • 2,927
  • 4
  • 14
  • 9
2

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

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Joel Feb 14 '14 at 18:30
  • Funny how similar to old versions of ember-simple-auth ember-session looks. Almost could get the impression it's largely just copied and relabeled... – marcoow Feb 18 '14 at 17:20
1

Please also take a look at : http://www.embercasts.com/

There are two screencasts there about authentication.

Thanks.

asaf000
  • 606
  • 6
  • 13