web-dev-qa-db-fra.com

passport.js RESTful auth

Comment gère-t-on l'authentification (locale et Facebook, par exemple) à l'aide de passport.js, via une API RESTful plutôt que via une interface Web?

Des problèmes spécifiques concernent le passage des données de callback à une réponse RESTful (JSON) par opposition à l’utilisation d’un res.send typique ({data: req.data}), la configuration d’un point de terminaison initial/login qui redirige vers Facebook (/ login ne peut pas être utilisé). accessible via AJAX, car il ne s'agit pas d'une réponse JSON - il s'agit d'une redirection vers Facebook avec rappel.

J'ai trouvé https://github.com/halrobertson/test-restify-passport-facebook , mais j'ai du mal à comprendre.

En outre, comment passport.js stocke-t-il les informations d’authentification? Le serveur (ou est-ce que c'est un service?) Est supporté par MongoDB, et je m'attendrais à ce que les informations d'identification (login & salted hash de pw) soient stockées ici, mais je ne sais pas si passport.js possède ce type de capacité.

155
ryanrhee

Il y a beaucoup de questions posées ici, et il semble que même si les questions sont posées dans le contexte de Node et passport.js), les vraies questions portent davantage sur le flux de travail que sur la manière de le faire avec un logiciel particulier. La technologie.

Utilisons l'exemple de configuration @Keith, modifié un peu pour plus de sécurité:

  • Serveur Web à https://example.com sert une application cliente Javascript d'une seule page
  • Service Web RESTful chez https://example.com/api fournit un support serveur à l'application client enrichi
  • Serveur implémenté dans Node et passport.js.
  • Le serveur a une base de données (toute sorte) avec une table "utilisateurs".
  • Le nom d'utilisateur/mot de passe et Facebook Connect sont proposés comme options d'authentification
  • Le client riche fait REST demandes en https://example.com/api
  • Il se peut que d’autres clients (applications téléphoniques, par exemple) utilisent le service Web à l'adresse https://example.com/api mais je ne connais pas le serveur Web à https://example.com.

Notez que j'utilise HTTP sécurisé. Ceci est à mon avis un must pour tout service disponible à la volée, car des informations sensibles telles que les mots de passe et les jetons d'autorisation passent entre le client et le serveur.

Authentification par nom d'utilisateur/mot de passe

Regardons d'abord comment fonctionne l'ancienne authentification.

  • L'utilisateur se connecte à https://example.com
  • Le serveur sert une application Javascript riche qui rend la page initiale. Quelque part dans la page il y a un formulaire de connexion.
  • De nombreuses sections de cette application à une seule page n'ont pas été renseignées en raison du fait que l'utilisateur n'a pas été connecté. Toutes ces sections ont un écouteur d'événement lors d'un événement de "connexion". Tout cela est du côté client, le serveur ne sait pas de ces événements.
  • L'utilisateur entre son identifiant et son mot de passe et appuie sur le bouton d'envoi, ce qui déclenche un gestionnaire Javascript pour enregistrer le nom d'utilisateur et le mot de passe dans les variables côté client. Ensuite, ce gestionnaire déclenche l'événement "login". Encore une fois, il s’agit d’une action côté client, les informations d’identification n’ont pas encore été envoyées au serveur .
  • Les écouteurs de l'événement "login" sont appelés. Chacun de ceux-ci doit maintenant envoyer une ou plusieurs demandes à l'API RESTful à l'adresse https://example.com/api pour obtenir les données spécifiques à l'utilisateur à afficher sur la page. Chaque demande envoyée au service Web comprendra le nom d'utilisateur et le mot de passe, éventuellement sous la forme d'une authentification HTTP Basic , car le service étant RESTful n'est pas autorisé à conserver l'état du client d'une demande à l'autre. suivant. Comme le service Web est sur HTTP sécurisé, le mot de passe est crypté en toute sécurité pendant le transit.
  • Le service Web à l'adresse https://example.com/api reçoit un ensemble de requêtes individuelles, chacune contenant des informations d'authentification. Le nom d'utilisateur et le mot de passe de chaque requête sont comparés à la base de données utilisateur. Si la requête est correcte, elle s'exécute et les données sont renvoyées au client au format JSON. Si le nom d'utilisateur et le mot de passe ne correspondent pas, une erreur est envoyée au client sous la forme d'un code d'erreur HTTP 401.
  • Au lieu de forcer les clients à envoyer un nom d'utilisateur et un mot de passe à chaque demande, vous pouvez avoir une fonction "get_access_token" dans votre service RESTful qui prend le nom d'utilisateur et le mot de passe et répond avec un jeton, qui est une sorte de hachage cryptographique unique et ayant une certaine expiration. date associée à elle. Ces jetons sont stockés dans la base de données avec chaque utilisateur. Ensuite, le client envoie le jeton d'accès dans les demandes suivantes. Le jeton d'accès sera ensuite validé par rapport à la base de données au lieu du nom d'utilisateur et du mot de passe.
  • Les applications clientes autres que les navigateurs, comme les applications téléphoniques, procèdent de la même manière que précédemment. Ils demandent à l'utilisateur de saisir ses informations d'identification, puis de les envoyer (ou un jeton d'accès généré à partir de ces informations) à chaque demande adressée au service Web.

Le point important à retenir de cet exemple est que les services Web RESTful nécessitent une authentification à chaque demande .

Une couche de sécurité supplémentaire dans ce scénario ajouterait une autorisation d'application client en plus de l'authentification de l'utilisateur. Par exemple, si vous avez le client Web, iOS et Android applications qui utilisent toutes le service Web, vous voudrez peut-être que le serveur sache lequel des trois clients le client d’une requête donnée est Ceci peut permettre à votre service Web de restreindre certaines fonctions à des clients spécifiques.Pour cela, vous pouvez utiliser des clés et des secrets d’API, voir cette réponse pour des idées à ce sujet.

Authentification Facebook

Le processus ci-dessus ne fonctionne pas pour Facebook Connect car la connexion via Facebook a un tiers, Facebook lui-même. La procédure de connexion nécessite que l'utilisateur soit redirigé vers le site Web de Facebook où les informations d'identification sont entrées en dehors de notre contrôle.

Voyons donc comment les choses changent:.

  • L'utilisateur se connecte à https://example.com
  • Le serveur sert une application Javascript riche qui rend la page initiale. Quelque part dans la page il y a un formulaire de connexion qui comprend un bouton "Connexion avec Facebook".
  • L'utilisateur clique sur le bouton "Connexion avec Facebook", qui est simplement un lien qui redirige vers (par exemple) https://example.com/auth/facebook.
  • Le https://example.com/auth/facebook La route est gérée par passport.js (voir le documentation )
  • Tout ce que l’utilisateur voit, c’est que la page change et maintenant, il se trouve dans une page hébergée sur Facebook où il doit se connecter et autoriser notre application Web. Ceci est complètement hors de notre contrôle.
  • L'utilisateur se connecte à Facebook et donne la permission à notre application. Facebook redirige maintenant vers l'URL de rappel que nous avons configurée dans la configuration du fichier passport.js. Suivant l'exemple de la documentation , https://example.com/auth/facebook/callback
  • Le gestionnaire de passeports.js pour le https://example.com/auth/facebook/callback route appellera la fonction de rappel qui reçoit le jeton d'accès Facebook et certaines informations utilisateur de Facebook, y compris l'adresse électronique de l'utilisateur.
  • Avec l'e-mail, nous pouvons localiser l'utilisateur dans notre base de données et stocker le jeton d'accès Facebook avec celui-ci.
  • La dernière chose que vous faites dans le rappel Facebook est de rediriger vers l'application client enrichi, mais cette fois, nous devons transmettre le nom d'utilisateur et le jeton d'accès au client afin qu'il puisse les utiliser. Cela peut être fait de différentes manières. Par exemple, des variables Javascript peuvent être ajoutées à la page via un moteur de modèle côté serveur, ou un cookie peut être renvoyé avec ces informations. (merci à @RyanKimber pour avoir signalé les problèmes de sécurité liés à la transmission de ces données dans l'URL, comme je l'avais initialement suggéré).
  • Alors maintenant, nous lançons l'application une page une fois de plus, mais le client a le nom d'utilisateur et le jeton d'accès.
  • L'application client peut déclencher immédiatement l'événement "login" et laisser les différentes parties de l'application demander les informations dont elles ont besoin au service Web.
  • Toutes les demandes envoyées à https://example.com/api inclura le jeton d'accès Facebook pour l'authentification ou le jeton d'accès propre à l'application généré à partir du jeton Facebook via une fonction "get_access_token" dans l'API REST.
  • Les applications autres que les navigateurs ont un peu plus de difficulté ici, car OAuth nécessite un navigateur Web pour la connexion. Pour vous connecter depuis un téléphone ou une application de bureau, vous devez démarrer un navigateur afin de pouvoir vous connecter. rediriger vers Facebook et, pire encore, vous avez besoin d’un moyen permettant au navigateur de renvoyer le jeton d’accès Facebook à l’application via un mécanisme quelconque.

J'espère que cela répond à la plupart des questions. Bien sûr, vous pouvez remplacer Facebook par Twitter, Google ou tout autre service d’authentification basé sur OAuth).

Je serais intéressé de savoir si quelqu'un a un moyen plus simple de gérer cela.

311
Miguel

J'apprécie grandement l'explication de @ Miguel avec le flux complet dans chaque cas, mais j'aimerais en ajouter quelques-unes dans la partie Authentification Facebook.

Facebook fournit un Javascript SDK que vous pouvez utiliser pour obtenir directement le jeton d'accès client-end, qui est ensuite transmis au serveur et utilisé pour extraire toutes les informations utilisateur de Facebook. Donc, vous n'avez pas besoin de ré-orienter fondamentalement.

De plus, vous pouvez également utiliser le même noeud final d'API pour les applications mobiles. Utilisez simplement le Android/iOS SDK pour Facebook, obtenez le code d’accès à Facebook du côté client et transmettez-le au serveur.

En ce qui concerne la nature sans état comme expliqué, lorsque get_access_token est utilisé pour générer un jeton et transmis au client, ce jeton est également stocké sur le serveur. Donc, c’est aussi bon qu’un jeton de session et je crois que cela le rend dynamique?

Juste mes 2 cents ..

11
Madhur

Voici un article génial que j'ai trouvé et qui peut vous aider à vous authentifier avec:

  • Facebook
  • Twitter
  • Google
  • Auth Local

Facile Node Authentification: configuration et local

3
myusuf