Victor
Victor

Reputation: 5353

Check if user is logged in before template load

I use angularjs with ui-router library. Lets say I have some routes for admin and some routes for user. If admin or user is logged in I want to show some page for them (admin.html for admin and user.html for user, for example), otherwise login.html

On the backend I have a special url, like /auth/status/, which gives me information about the user (if he's logged and which role he has)

There are some situations I can't figure out how to handle:

I go to '/' url. The application loads. I have a run method for my app module. But how can I check if the user is logged in, when it happens asynchronously? Well, I have this and it works somehow, but I'm not sure if this is a good solution:

    app.config(['$stateProvider', '$routeProvider',
    function($stateProvider, $routeProvider) {
        $stateProvider
            .state('admin', {
                abstract: true,
                url: '/',
                templateUrl: 'templates/admin.html'
            })
            .state('admin.desktop', {
                url: 'desktop',
                templateUrl: 'templates/desktop.html'
            });
    }]);


    app.run([
    '$http', 
    '$rootScope', 
    '$location', 
    '$state', 
    'userRoles',
    function($http, $rootScope, $location, $state, userRoles) {
        var DEFAULT_ADMIN_STATE      = 'admin.desktop';

        var promise = $http.get('/auth/status/');

        promise.then(function(response) {
            $rootScope.isLogged = response.data.logged;
            $rootScope.userRole = userRoles[response.data.role];

            if (!$rootScope.isLogged) {
                $state.transitionTo('login');
            } else {
                switch (response.data.role) {
                    case 'admin': $state.transitionTo(DEFAULT_ADMIN_STATE);      break;
                }
            }
        }, function(response) {
            $location.path('/login');
        });
}]);

Though I don't understand: if I go to / url I should get an error because it's abstract. Instead when $http.get request is resolved (I put 2 seconds sleep in backend to check that) I transition to admin.desktop state. I'm confused what happens in which order: state loads template or app.run function with some ajax requests...

The main question is, when I go to /#/desktop how can I first check if user is logged (send a request to /admin/auth/ and check what it returns) and only then decide what to do (transition to login or desktop state)? I found Delaying AngularJS route change until model loaded to prevent flicker this, but again still a little fuzzy for me. Resolve property seems like a solution when I want to load a list of entities and then show the template. But I want to have some "before" function for ALL states which just checks if user is logged and has a correspond role (one moment: I do not want to use /admin/entites or /user/entities urls, want to have just /entitites. As I get it several states may have the same url). So basically it looks like if I go to /someurl I want to run method wait until it gets ajax response and after that transition to some state. Instead the state corresponding to /someurl load a template...

Also I found an article about authentication in angular but author uses cookies which is not async thing

Update: when I use cookies for checking if user is logged and I go to /#/desktop I still have it rendered, and $state.transitionTo doesn't work..

Upvotes: 3

Views: 2280

Answers (1)

S Panfilov
S Panfilov

Reputation: 17551

You should check it before page load:

I cannot write full example now, but in common you should do like this:

.run([ ..., function(....) {
    $scope.$on('$routeChangeStart', function(next, current) { 
        ... check cookie here ...
    });
}]);

Upvotes: 1

Related Questions