maze
maze

Reputation: 2284

Proper way to handle authentication

I have read a lot of different examples on how to implement authentication in an Angular app. I am using Firebase Simple Login as a (No-)Backend.

Users should only see any content of my app, once they are logged in. If they are logged out, all they can see is /auth/login and /auth/register. Currently, I have the following solution which works. But:

1) I am not sure whether this is bullet-proof because...

2) ... when I open /home manually while NOT logged in, I correctly get redirected to /auth/login but the HomeCtrl gets executed anyway. No sensitive data is exposed because no data is returned from the Backend, but there must be a way to NOT execute the controller at all if I am logged out?

3) Everytime I expose sensitive data, do I have to check inside my controller if the user is authenticated over and over again?

Bonus question: How do I redirect to /home after successful login? Currently, inside my AuthService I do $location.path('home'); on successful login, but this doesn't account for the state?!

My app.js:

angular.module('myApp', ['ionic', 'firebase', 'myApp.services', 'myApp.controllers'])

.run(function($rootScope, $location, AuthService) {
  $rootScope.$on('$stateChangeStart', function (ev, to, toParams, from, fromParams) {     

  /**
   * AuthService.isLoggedIn() returns TRUE or FALSE
   * depending on whether user authenticated successfully 
   * against the Firebase backend
   */

    // redirect to login 
    if (!AuthService.isLoggedIn() && to.name !== 'auth.register') {
      $location.path('/auth/login');
    }
  });
})

.config(function($stateProvider, $urlRouterProvider) {

  $stateProvider

    .state('auth', {
      url: "/auth",
      abstract: true,
      templateUrl: "templates/auth-tabs.html",
      controller: 'AuthCtrl'
    })

    .state('auth.login', {
      url: '/login',
      views: {
        'login-tab': {
          templateUrl: 'templates/auth-login.html'
        }
      }
    })

    .state('auth.register', {
      url: '/register',
      views: {
        'register-tab': {
          templateUrl: 'templates/auth-register.html'
        }
      }
    })

    .state('home', {
      url: '/home',
      templateUrl: 'templates/home.html',
      controller: 'HomeCtrl'
    });

  $urlRouterProvider.otherwise('/home');

});

Upvotes: 2

Views: 763

Answers (1)

guzart
guzart

Reputation: 3730

The way I've implemented it is by handling a 401 http server response, because I don't want to worry about checking for the user authentication state, I prefer letting the server handle that. That being said.

Documentation on $urlRouter.sync() specifies that if you prevent the default event, you may manually trigger the succesChange

angular.module('app', ['ui.router']);
  .run(function($rootScope, $urlRouter) {
    $rootScope.$on('$locationChangeSuccess', function(evt) {
      // Halt state change from even starting
      evt.preventDefault();
      // Perform custom logic
      var meetsRequirement = ...
      // Continue with the update and state transition if logic allows
      if (meetsRequirement) $urlRouter.sync();
    });
});

$urlRouter documentation

Upvotes: 1

Related Questions