Maison > interface Web > js tutoriel > le corps du texte

Exemple de code détaillé sur la façon d'utiliser AngularJS pour l'authentification

伊谢尔伦
Libérer: 2017-07-20 10:46:10
original
1564 Les gens l'ont consulté

Authentification d'identité

La méthode d'authentification d'identité la plus courante consiste à se connecter à l'aide d'un nom d'utilisateur (ou d'un e-mail) et d'un mot de passe. Cela signifie mettre en place un formulaire de connexion afin que les utilisateurs puissent se connecter avec leurs informations personnelles. Le formulaire ressemble à ceci :

<form name="loginForm" ng-controller="LoginController"
   ng-submit="login(credentials)" novalidate>
 <label for="username">Username:</label>
 <input type="text" id="username"
     ng-model="credentials.username">
 <label for="password">Password:</label>
 <input type="password" id="password"
     ng-model="credentials.password">
 <button type="submit">Login</button>
</form>
Copier après la connexion

Comme il s'agit d'un formulaire alimenté par Angular, nous utilisons la directive ngSubmit pour déclencher la fonction lors du téléchargement du formulaire. Notez que nous transmettons les informations personnelles dans la fonction de formulaire de téléchargement au lieu d'utiliser directement l'objet $scope.credentials. Cela rend la fonction plus facile à tester unitairement et réduit le couplage de la fonction à la portée actuelle du contrôleur. Le contrôleur ressemble à ceci :

.controller(&#39;LoginController&#39;, function ($scope, $rootScope, AUTH_EVENTS, AuthService) {
 $scope.credentials = {
  username: &#39;&#39;,
  password: &#39;&#39;
 };
 $scope.login = function (credentials) {
  AuthService.login(credentials).then(function (user) {
   $rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
   $scope.setCurrentUser(user);
  }, function () {
   $rootScope.$broadcast(AUTH_EVENTS.loginFailed);
  });
 };javascript:void(0);
})
Copier après la connexion

Nous remarquons qu’il y a ici un manque de logique réelle. Ce contrôleur est conçu ainsi pour découpler la logique d'authentification du formulaire. C'est une bonne idée d'extraire autant de logique que possible de notre contrôleur et de tout mettre dans les services. Le contrôleur d'AngularJS ne doit gérer que les objets dans $scope (en utilisant la surveillance ou l'opération manuelle) au lieu d'assumer trop de tâches trop lourdes.

Notification des changements de session

L'authentification de l'identité affectera l'état de l'ensemble de l'application. Pour cette raison, je préfère utiliser des événements (en utilisant $broadcast) pour notifier les modifications de session utilisateur. C'est une bonne idée de définir tous les codes d'événement possibles à mi-chemin. J'aime utiliser des constantes pour ce faire :

.constant(&#39;AUTH_EVENTS&#39;, {
 loginSuccess: &#39;auth-login-success&#39;,
 loginFailed: &#39;auth-login-failed&#39;,
 logoutSuccess: &#39;auth-logout-success&#39;,
 sessionTimeout: &#39;auth-session-timeout&#39;,
 notAuthenticated: &#39;auth-not-authenticated&#39;,
 notAuthorized: &#39;auth-not-authorized&#39;
})
Copier après la connexion

Une bonne caractéristique des constantes est qu'elles peuvent être injectées à d'autres endroits à volonté, tout comme les services. Cela rend les constantes facilement appelables par notre test unitaire. Les constantes vous permettent également de les renommer facilement ultérieurement sans avoir à modifier de nombreux fichiers. La même astuce fonctionne avec les rôles d'utilisateur :

.constant(&#39;USER_ROLES&#39;, {
 all: &#39;*&#39;,
 admin: &#39;admin&#39;,
 editor: &#39;editor&#39;,
 guest: &#39;guest&#39;
})
Copier après la connexion

Si vous souhaitez accorder les mêmes autorisations aux éditeurs et aux administrateurs, il vous suffit de remplacer « éditeur » par « admin ».

L'AuthService

La logique liée à l'authentification et à l'autorisation d'identité (contrôle d'accès) est mieux placée dans le même service :

.factory(&#39;AuthService&#39;, function ($http, Session) {
 var authService = {};

 authService.login = function (credentials) {
  return $http
   .post(&#39;/login&#39;, credentials)
   .then(function (res) {
    Session.create(res.data.id, res.data.user.id,
            res.data.user.role);
    return res.data.user;
   });
 };

 authService.isAuthenticated = function () {
  return !!Session.userId;
 };

 authService.isAuthorized = function (authorizedRoles) {
  if (!angular.isArray(authorizedRoles)) {
   authorizedRoles = [authorizedRoles];
  }
  return (authService.isAuthenticated() &&
   authorizedRoles.indexOf(Session.userRole) !== -1);
 };
 return authService;
})
Copier après la connexion

Afin de m'éloigner davantage des préoccupations d'authentification d'identité, j'utilise un autre service (un objet singleton, utilisant le style service) pour sauvegarder les informations de session de l'utilisateur. Les détails des informations de session dépendent de l'implémentation du backend, mais je vais donner un exemple plus général :

.service(&#39;Session&#39;, function () {
 this.create = function (sessionId, userId, userRole) {
  this.id = sessionId;
  this.userId = userId;
  this.userRole = userRole;
 };
 this.destroy = function () {
  this.id = null;
  this.userId = null;
  this.userRole = null;
 };
 return this;
})
Copier après la connexion

Une fois l'utilisateur connecté, ses informations doivent être affichées à certains endroits (comme l'avatar de l'utilisateur ou quelque chose du genre dans le coin supérieur droit). Pour y parvenir, l'objet utilisateur doit être référencé par l'objet $scope, de préférence un objet qui peut être appelé globalement. Bien que $rootScope soit le premier choix évident, j'essaie de m'empêcher d'utiliser trop $rootScope (en fait, je n'utilise $rootScope que pour les diffusions d'événements globaux). La façon dont je préfère procéder est de définir un contrôleur au niveau du nœud racine de l'application, ou ailleurs au moins au-dessus de l'arborescence DOM. Les balises sont un bon choix :

<body ng-controller="ApplicationController">
 ...
</body>
Copier après la connexion

ApplicationController est un conteneur pour la logique globale de l'application et une option pour exécuter la méthode run d'Angular. Par conséquent, il sera à la racine de l’arborescence $scope, et toutes les autres étendues en hériteront (à l’exception de la portée d’isolation). C'est un bon endroit pour définir l'objet currentUser :

.controller(&#39;ApplicationController&#39;, function ($scope,
                        USER_ROLES,
                        AuthService) {
 $scope.currentUser = null;
 $scope.userRoles = USER_ROLES;
 $scope.isAuthorized = AuthService.isAuthorized;

 $scope.setCurrentUser = function (user) {
  $scope.currentUser = user;
 };
})
Copier après la connexion

Nous n'attribuons pas réellement l'objet currentUser, nous initialisons simplement les propriétés de portée afin que currentUser soit accessible ultérieurement. Malheureusement, nous ne pouvons pas simplement attribuer une nouvelle valeur à currentUser dans la portée enfant car cela créerait une propriété shadow. C'est le résultat du passage de types primitifs (chaînes, nombres, booléens, non définis et nuls) par valeur plutôt que par référence. Pour empêcher les propriétés d'ombre, nous devons utiliser des fonctions de définition. Si vous souhaitez en savoir plus sur les portées angulaires et l'héritage prototypique, lisez Comprendre les portées.

Contrôle d'accès

L'authentification d'identité, c'est-à-dire le contrôle d'accès, n'existe pas réellement dans AngularJS. Parce que nous sommes une application client, tout le code source est entre les mains de l'utilisateur. Il n'existe aucun moyen d'empêcher les utilisateurs de falsifier le code pour obtenir une interface authentifiée. Tout ce que nous pouvons faire, c'est montrer les commandes. Si vous avez besoin d'une véritable authentification, vous devrez le faire côté serveur, mais cela dépasse le cadre de cet article.

Restreindre l'affichage des éléments

AngularJS a des directives pour contrôler l'affichage ou le masquage des éléments en fonction de la portée ou des expressions : ngShow, ngHide, ngIf et ngSwitch. Les deux premiers masqueront l'élément à l'aide d'un attribut