web-dev-qa-db-fra.com

AngularJS - Vérifier si un utilisateur est authentifié, puis le router vers la bonne page

Ce que je cherche à faire lorsqu'un utilisateur se présente sur la page index.html, il me faut le module de connexion pour faire 2 choses:

  1. J'ai besoin de cela pour vérifier si un utilisateur est authentifié (ce qui, je pense, a déjà commencé avec "function authService") si l'utilisateur a un jeton valide, puis changez la vue ui en dashboard/dashboard.html et si la clé n'est pas valide ou bien il n'y a pas de clé du tout, puis chargez login/login.html dans ui-view.

  2. Une fois qu'ils se sont connectés avec succès, je veux qu'ils soient routés vers "dashboard/dashboard.html"

Voici mon script de connexion:

function authInterceptor(API) {
  return {
    request: function(config) {
      if(config.url.indexOf(API) === 0) {
        request.headers = request.headers || {};
        request.headers['X-PCC-API-TOKEN'] = localStorage.getItem('token');
      }
      return config;
    }
  } 
}

function authService(auth) {
  var self = this;
  self.isAuthed = function() {
    localStorage.getItem('token');
  }
}

function userService($http, API) {

  $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;';
  $http.defaults.transformRequest = [function(data) {
      return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
    }];

  var self = this;

  self.login = function(username, pwd, ctrl) {
    ctrl.requestdata = API + '/winauth' + '; with ' + username;
    return $http.post(API + '/winauth', {
        username: username,
        pwd: pwd
      })
  };

  var param = function(obj) {
    var query = '', name, value, fullSubName, subName, subValue, innerObj, i;

    for(name in obj) {
      value = obj[name];

      if(value instanceof Array) {
        for(i=0; i<value.length; ++i) {
          subValue = value[i];
          fullSubName = name + '[' + i + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + '&';
        }
      }
      else if(value instanceof Object) {
        for(subName in value) {
          subValue = value[subName];
          fullSubName = name + '[' + subName + ']';
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + '&';
        }
      }
      else if(value !== undefined && value !== null)
        query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
    }

    return query.length ? query.substr(0, query.length - 1) : query;
  };

}

function LoginCtrl(user) {
  var self = this;

  function handleRequest(res) {
    self.responsedata = res;
    self.message = res.data.message;

    var authToken = res.data.auth_token;
    localStorage.setItem('token', authToken);
  }

  self.login = function() {
    this.requestdata = 'Starting request...';
    user.login(self.username, self.pwd, self)
      .then(handleRequest, handleRequest)
  }
}

// Login Module
var login = angular.module('login', ["ui.router"])

login.factory('authInterceptor', authInterceptor)
login.service('user', userService)
login.service('auth', authService)
login.constant('API', 'http://myserver.com/api')

EDIT - J'ai ajouté ceci dans mon contrôleur de connexion pour fournir les routes de connexion

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

  $httpProvider.interceptors.Push('authInterceptor');

  $urlRouterProvider.otherwise('/login');

  $stateProvider
  // HOME STATES AND NESTED VIEWS ========================================
  .state('login', {
    url: '/login',
    templateUrl: 'login/login.html',
    controller: "mainLogin",
    controllerAs: "log"
  })           
  // nested list with just some random string data
  .state('dashboard', {
    url: '/dashboard',
    templateUrl: 'dashboard/dashboard.html',
  })

})

login.controller('mainLogin', LoginCtrl)

Voici mon index.html:

EDIT - J'ai supprimé "ng-include" et ajouté "ng-view" pour contrôler les itinéraires.

<body ng-app="login" ng-controller="mainLogin as log" class="loginPage">

  <div class="main" ui-view></div>

</body>

Comme vous pouvez le constater, une fonction vérifie le jeton dans la mémoire de stockage de l'utilisateur:

function authService(auth) {
  var self = this;
  self.isAuthed = function() {
    localStorage.getItem('token');
  }
}

Et je le charge dans le module en tant que service:

login.service('auth', authService)

C'est là que je suis coincé. Je ne sais pas où aller d'ici. Je ne sais même pas si j'utilise correctement ma fonction authService. J'en apprends encore beaucoup sur AngularJS, il est donc facile pour moi de rester bloqué. :)

Une autre chose que vous remarquerez est dans mon fichier index.html. Je charge juste le partial "login/login.html" par défaut. J'en ai besoin de charger login.html ou dashboard.html, selon qu'ils soient connectés ou non. Et puis dirigez-les également vers dashboard.html une fois qu’ils se sont connectés avec succès.

Le script fonctionne parfaitement dans la mesure où il frappe l'API d'authentification, authentifie l'utilisateur puis stocke une clé d'authentification valide sur son stockage local.

Quelqu'un sait comment je peux accomplir cela?

20
agon024

ok je vois que vous utilisez ui.router alors travaillons dans ce cadre.

Tu veux

  1. vérifier si un utilisateur est connecté
  2. rediriger l'utilisateur vers une vue

Ce que vous cherchez, c'est resolve:{loggedIn: checkLoggedInFn}

afin que votre route pour le tableau de bord pourrait être quelque chose comme

.state('dashboard', {
 url: '/dashboard',
 templateUrl: 'dashboard/dashboard.html',
 resolve: {
    loggedIn: function(){
       //do your checking here
    }
  }
})

en gros, cela signifie que le contrôleur n'instanciera pas jusqu'à ce que chaque résolution soit résolue (vous pouvez donc utiliser une promesse ici, par exemple), puis la valeur est transmise au contrôleur en tant que paramètre. Vous pouvez alors effectuer les opérations suivantes:

if(!loggedIn){
   $state.go('login');
}
2
Dacheng

Vous avez deux préoccupations distinctes à traiter. La première consiste à pouvoir déterminer si vous êtes connecté. En supposant que l'utilisateur ait besoin d'être connecté pour n'importe quel état, à l'exception de l'état de connexion, vous devez le mettre en œuvre de cette manière en écoutant les événements $ stateChangeState et en vérifiant que l'utilisateur est connecté. dans:

login.run(function($state, authService) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        var authToken = authService.isAuthed();
        if (!authToken && toState !== 'login') {
            //not logged in, so redirect to the login view instead of the view
            //the user was attempting to load
            event.preventDefault();
            $state.go('login');

        } 
    })
});

Cela les mettra sur l'état de connexion s'ils ne sont pas déjà connectés. 

La deuxième partie consiste à rediriger vers la vue correcte après la connexion, comme vous le feriez dans votre contrôleur de connexion:

function LoginCtrl(user, $state) {
    var self = this;

    function handleRequest(res) {
        self.responsedata = res;
        self.message = res.data.message;

        var authToken = res.data.auth_token;
        localStorage.setItem('token', authToken);

        //after successful login, redirect to dashboard
        $state.go('dashboard');
    }

    self.login = function() {
        this.requestdata = 'Starting request...';
        user.login(self.username, self.pwd, self)
                .then(handleRequest, handleRequest)
    }
}
2
mcgraphix

Vous devez gérer la logique à l'intérieur de votre contrôleur de connexion spécifiquement ici:

 self.login = function() {
    this.requestdata = 'Starting request...';
    user.login(self.username, self.pwd, self)
      .then(handleRequest, handleRequest)
  }

À l'intérieur du rappel pour le succès de la connexion, vous feriez simplement un changement d'état pour envoyer l'utilisateur à l'état correct.

1
Garuuk

Votre service est correct et il figure sur le module de connexion, mais vous ne l'utilisez nulle part. Vous devez injecter votre service dans le contrôleur pour effectuer les tâches que vous souhaitez. Dans votre authService, vous obtenez un article de localstorage mais vous ne renvoyez rien, par exemple, vous avez votre service de connexion. 

function authService(auth) {
  var self = this;
  self.isAuthed = function() {       
   return localStorage.getItem('token');
  }
}
 //here you can inject your auth service to get it work as you want
function LoginCtrl(user, auth) {
  var self = this;

  function handleRequest(res) {
    self.responsedata = res;
    self.message = res.data.message;

    var authToken = res.data.auth_token;
    localStorage.setItem('token', authToken);
  }

  self.login = function() {
    this.requestdata = 'Starting request...';
    user.login(self.username, self.pwd, self)
      .then(handleRequest, handleRequest)
  }
}
login.service('auth', authService)
1
Jorawar Singh
function authService(auth) {
var self = this;
self.isAuthed = function() {
**localStorage.getItem('token');**
}  
}

Où obtenez-vous l'élément localstorage? La LValue est manquante.

Au niveau le plus élémentaire, vous pouvez gérer une vérification de cet élément - jeton - dans la page Tableau de bord, au moment du chargement de la page et si elle est nulle, à savoir. vide, puis redirige/dirige l'utilisateur vers la page de connexion. Btw, utilisez le sessionStorage plutôt que le localStorage car le précédent sera vidé dès que la session du navigateur sera fermée.

Il existe des moyens plus élégants et plus simples de le réaliser, comme Passport . Avez-vous vérifié? C'est aussi simple que cela:

app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect:'/login'}));
1
user2347763

Il existe un moyen simple de réaliser ce que vous voulez pour votre application en utilisant PassportJs .

La documentation est assez simple et facile à mettre en œuvre.

Vous pouvez également consulter ce didacticiel pour mettre en œuvre l'authentification à l'aide de Passport. Ce tutoriel explique de manière très simple comment effectuer l'authentification pour votre application.

1
Ravi Shankar

Votre code ne vérifie pas les modifications d'URL ni les itinéraires de manière transversale.

N'oubliez pas que l'authentification et l'autorisation sont des préoccupations transversales. Cela étant dit, Angular vous permet d'intercepter les appels d'acheminement en écoutant $ routeChangeStart. Votre "intercepteur" devrait y être ajouté. Vous pouvez ensuite rediriger le routeur vers la vue requise en y routant manuellement. Jetez un coup d'œil à la solution issue d'un précédent thread de débordement de pile .

1
Roan Bester

Dans authInterceptor ajoute du code pour la réponse. Alors:

return {
    request: function(config) {

        if(config.url.indexOf(API) === 0) {
        request.headers = request.headers || {};
        request.headers['X-PCC-API-TOKEN'] =  localStorage.getItem('token');
        }

        return config;
    },
    response: function(response) {

        //ok response - code 200

        return response;
    },
    responseError: function(response){

       //wrong response - different response code
    }
};

Sur le serveur, vérifiez l'entête http X-PCC-API-TOKEN et si est incorrect (aucune authentification), la réponse doit avoir un code différent, tel que 403. La méthode responseError sera donc exécutée dans interceptor.

    responseError: function(response){

       //wrong response - different response code
       if (response.status === 403) {
            alert("No rights to page");//your code for no auth

            //redirect to different route
            $injector.get('$state').transitionTo('login');//use injector service            
            return $q.reject(response);//return rejection - use $q
        }

    }
1
Maciej Sikora

Pour ce faire, utilisez simplement https://github.com/Emallates/ng-enoa-auth package. Vous devez simplement l'inclure dans votre application, rien d'autre.

0
9me