0

I'm using app.run() in my AngularJS app to check whether a user is logged in before displaying the site to block access to various sites for non-registered users. I tried doing it with a promise because before, whenever I reloaded the page the isLoggedIn function would return false the getStatus hasn't returned the answer from the server yet.

Now using the promise, the site just calls itself in a loop forever, I guess because the process just repeats itself when the promise is resolved. Where am I going wrong and how could I fix this? Thanks in advance, help is much appreciated!

This is my code in app.js:

app.run(function($rootScope, $state, authService){
    $rootScope.$on('$stateChangeStart', function(event, next, nextParams, from, fromParams){
      event.preventDefault();
      authService.getUserStatus().then(function(){
        console.log(authService.isLoggedIn());
        if(next.access.restricted && !authService.isLoggedIn()){
          $state.go('index', {}, { reload: true });
        } else {
          $state.go(next, {}, { reload: true });
        }
      });
    });
  });

Here's the service authService.js:

(function(){
  var app = angular.module('labelcms');
  app.factory('authService', ['$q', '$timeout', '$http', function($q, $timeout, $http){

    var user = null;

    var isLoggedIn = function(){
      if(user){
        return true;
      } else {
        return false;
      }
    };

    var getUserStatus = function(){
      var deferred = $q.defer();

      $http.get('/api/user/status')
        .success(function(data){
          if(data.status){
            user = data.status;
            deferred.resolve();
          } else {
            user = false;
            deferred.resolve();
          }
        })
        .error(function(data){
          console.log('Error: ' + data);
          user = false;
          deferred.resolve();
        });

      return deferred.promise;
    };

    return ({
      isLoggedIn: isLoggedIn,
      getUserStatus: getUserStatus,
      login: login,
      logout: logout,
      signup: signup
    });

  }]);
})();
cursedphil
  • 85
  • 1
  • 4
  • shouldn't need to make request, or prevent default, if user is already logged in – charlietfl Mar 02 '16 at 00:16
  • But user is set back to false each time the page gets reloaded, so I have to call the api on each page request. Is there a better way to store the user login in angular? – cursedphil Mar 02 '16 at 00:20
  • Then what is the point of `isLoggedIn()`? And why would you need to check for areas that are not restricted? Best way is use a `resolve` on parent state of router where parent is for restricted areas. Child states can't be accessed if parent resolve gets rejected – charlietfl Mar 02 '16 at 00:23
  • Avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572)! And resolve your promise with the `user` value, instead of passing it around via a separate getter! – Bergi Mar 02 '16 at 00:24
  • @Bergi could you translate this into my code? Sorry, I'm quite new to the mean stack and was gathering the code from various tutorials. Would be thankful about help! :) – cursedphil Mar 02 '16 at 00:38
  • @cursedphil: Basically just `function getUserStatus() { return $http.get('/api/user/status').then(Boolean, function(data) { console.log("Error", data); return false;}); }` and `authService.getUserStatus().then(function(user){ console.log(user); … })` – Bergi Mar 02 '16 at 01:09
  • @Bergi gotcha! Thank you! – cursedphil Mar 02 '16 at 01:20

1 Answers1

0

It loops because every time you execute $state.go(next, {}, { reload: true }); it will hit your $rootScope.$on again.

I would check if we actually are on restricted route before you go into your security service.

app.run(function($rootScope, $state, authService){
    $rootScope.$on('$stateChangeStart', function(event, next, nextParams, from, fromParams){
      if(!next.access.restricted) return;
      authService.getUserStatus().then(function(){
        console.log(authService.isLoggedIn());
        if(!authService.isLoggedIn()){
          $state.go('index', {}, { reload: true });
      });
    });
  });
SSH
  • 2,533
  • 16
  • 21
  • That's what I was assuming, I just didn't know any way around. The return after checking if it is a restricted state is pretty sleek, but wouldn't this just get stuck in a loop again once it hits a restricted route? – cursedphil Mar 02 '16 at 00:48
  • Well if you want to prevent default and then redirect again -- it would, I removed prevent default in later edit. So now it will only stuck there if your index route is restricted (it should not be) – SSH Mar 02 '16 at 00:53
  • 1
    don't forget to prevent default while making auth request. Nothing here to stop the route changing – charlietfl Mar 02 '16 at 01:25