AngularJS: Retain Login information when page refresh

2.7k Views Asked by At

I am trying to retain the user information when page refresh. I used cookieStore for this purpose. So my run module in the Angular App looks like this.

.run(['$rootScope', '$cookieStore', '$state', function($rootScope, $cookieStore, $state) {
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, $location){
        var requireLogin = toState.data.requireLogin;

            if(typeof $rootScope.user == 'undefined'){
                $rootScope.user=$cookieStore.get("user");
                $rootScope.sessionid=$cookieStore.get("session");
            }
            if(requireLogin && typeof $rootScope.user === 'undefined'){
                event.preventDefault();
                 $state.go('login', null, {notify: false}).then(function(state) {
                        $rootScope.$broadcast('$stateChangeSuccess', state, null);
                 });
            }
    });

Two main things I wanted to achieve from this is,

  1. Have to get the user and sessioninfo from the browser's local storage, when page refresh.
  2. If user is undefined, then it has to be redirected to the login page. It is for restricting the users to go to intermediate pages without login.

If user is undefined, and data is not available in the local storage, the first if statement gives error and the second if statement doesnot work.

So when the user tries to visit any page the first time without going to login page, it is not redirecting to the login page, because the code failed in first if statement, the second if not working.

How can I achieve both the functionalities together?

Thank you

2

There are 2 best solutions below

1
On

You can create an authInterceptor factory and push it in interceptors.

This method will always check if user is logged in or not on each page and will throw user on login page if he is not authenticated

For purposes of global error handling, authentication, or any kind of synchronous or asynchronous pre-processing of request or postprocessing of responses, it is desirable to be able to intercept requests before they are handed to the server and responses before they are handed over to the application code that initiated these requests. The interceptors leverage the promise APIs to fulfill this need for >both synchronous and asynchronous pre-processing.

Learn more about Interceptors

'use strict';

angular.module('app', [
    'ngCookies',
    'ngResource',
    'ngSanitize',
    'ngRoute'
  ])
  .config(function($routeProvider, $locationProvider, $httpProvider) {
    $routeProvider
      .otherwise({
        redirectTo: '/'
      });

    $httpProvider.interceptors.push('authInterceptor');
  })

.factory('authInterceptor', function($rootScope, $q, $cookieStore, $location) {
  return {
    // Add authorization token to headers
    request: function(config) {
      config.headers = config.headers || {};
      if ($cookieStore.get('token')) {
        config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
      }
      return config;
    },

    // Intercept 401s and redirect you to login
    responseError: function(response) {
      if (response.status === 401) {
        $location.path('/login');
        // remove any stale tokens
        $cookieStore.remove('token');
        return $q.reject(response);
      } else {
        return $q.reject(response);
      }
    }
  };
})

.run(function($rootScope, $location, Auth) {
  // Redirect to login if route requires auth and you're not logged in
  $rootScope.$on('$routeChangeStart', function(event, next) {
    Auth.isLoggedInAsync(function(loggedIn) {
      if (next.authenticate && !loggedIn) {
        $location.path('/login');
      }
    });
  });
})

.factory('Auth', function Auth($location, $rootScope, $http, User, $cookieStore, $q) {
    var currentUser = {};
    if ($cookieStore.get('token')) {
      currentUser = User.get();
    }

    return {
      /**
       * Gets all available info on authenticated user
       *
       * @return {Object} user
       */
      getCurrentUser: function() {
        return currentUser;
      },

      /**
       * Check if a user is logged in
       *
       * @return {Boolean}
       */
      isLoggedIn: function() {
        return currentUser.hasOwnProperty('role');
      },

      /**
       * Waits for currentUser to resolve before checking if user is logged in
       */
      isLoggedInAsync: function(cb) {
        if (currentUser.hasOwnProperty('$promise')) {
          currentUser.$promise.then(function() {
            cb(true);
          }).catch(function() {
            cb(false);
          });
        } else if (currentUser.hasOwnProperty('role')) {
          cb(true);
        } else {
          cb(false);
        }
      }
    };
  })

 .factory('User', function($resource) {
      return $resource('/api/users/:id/:controller', {
          id: '@_id'
        }
      });
  });

With Above Mechanism, you can use Auth service to get user info in any controller or directives as:

.controller('MainCtrl', function ($scope, Auth) {
  $scope.currentUser = Auth.getCurrentUser;
});

in template file:

<div ng-controller="MainCtrl">
  <p> Hi {{currentUser().name}}!</p>
</div>

Note: You need to create a proper REST API in order to get correct user data

2
On

I would look into using ngStorage. I use the sessionStorage object which will retain the data even on refresh. If you need further implentation example please let me know but the documentation is great.

https://github.com/gsklee/ngStorage