Avec la popularité croissante des applications à page unique, des applications mobiles et des services d'API RESTful, la voie développeurs web l'écriture de code back-end a considérablement changé. Avec des technologies comme AngularJS et BackboneJS, nous ne passons plus beaucoup de temps à créer du balisage, mais nous construisons des API que nos applications frontales consomment. Notre back-end concerne davantage la logique métier et les données, tandis que la logique de présentation est déplacée exclusivement vers les applications frontales ou mobiles. Ces changements ont conduit à de nouvelles façons de mettre en œuvre l'authentification dans les applications modernes.
L'authentification est l'une des parties les plus importantes de toute application Web. Pendant des décennies, les cookies et l'authentification par serveur ont été la solution la plus simple. Cependant, la gestion de l'authentification dans les applications mobiles et à page unique modernes peut être délicate et exiger une meilleure approche. Les solutions les plus connues aux problèmes d'authentification pour les API sont les OAuth 2.0 et le Jeton Web JSON (JWT).
Avant d'entrer dans ce didacticiel sur les jetons Web JSON, qu'est-ce qu'un JWT exactement?
Un jeton Web JSON est utilisé pour envoyer des informations qui peuvent être vérifiées et approuvées au moyen d'une signature numérique. Il comprend un objet JSON compact et sécurisé pour les URL, qui est signé de manière cryptographique pour vérifier son authenticité, et qui peut également être crypté si la charge utile contient des informations sensibles.
En raison de sa structure compacte, JWT est généralement utilisé dans HTTP Authorization
en-têtes ou paramètres de requête d'URL.
Un JWT est représenté comme une séquence de base64url valeurs codées séparées par des caractères de point.
Voici un exemple de jeton JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0. yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
L'en-tête contient les métadonnées du jeton et contient au minimum le type de signature et l'algorithme de chiffrement. (Vous pouvez utiliser un Formateur JSON outil pour embellir l'objet JSON.)
Exemple d'en-tête
{ 'alg': 'HS256', 'typ': 'JWT' }
Cet exemple d'en-tête JWT déclare que l'objet codé est un jeton Web JSON et qu'il est signé à l'aide de l'algorithme HMAC SHA-256.
Une fois qu'il est encodé en base64, nous avons la première partie de notre JWT.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Dans le contexte de JWT, une revendication peut être définie comme une déclaration concernant une entité (généralement, l'utilisateur), ainsi que des métadonnées supplémentaires sur le jeton lui-même. La revendication contient les informations que nous voulons transmettre et que le serveur peut utiliser pour gérer correctement l'authentification par jeton Web JSON. Nous pouvons fournir plusieurs réclamations; ceux-ci comprennent les noms de revendications enregistrées, les noms de revendications publiques et les noms de revendications privées.
Réclamations JWT enregistrées
Ce sont les créances enregistrées dans le Registre des revendications de jetons Web IANA JSON . Ces revendications JWT ne sont pas destinées à être obligatoires, mais plutôt à fournir un point de départ pour un ensemble de revendications utiles et interopérables.
Ceux-ci inclus:
Réclamations publiques
Les revendications publiques doivent avoir des noms résistants aux collisions. En faisant du nom un URI ou un URN, les collisions de dénomination sont évitées pour les JWT où l'expéditeur et le destinataire ne font pas partie d'un réseau fermé.
Un exemple de nom de revendication public pourrait être: https://www.toptal.com/jwt_claims/is_admin
, et la meilleure pratique consiste à placer un fichier à cet emplacement décrivant la revendication afin qu'il puisse être déréférencé pour la documentation.
Réclamations privées
Les noms de revendication privés peuvent être utilisés dans des endroits où les JWT ne sont échangés que dans un environnement fermé entre des systèmes connus, comme à l'intérieur d'une entreprise. Ce sont des affirmations que nous pouvons définir nous-mêmes, comme les identifiants d'utilisateurs, les rôles d'utilisateurs ou toute autre information.
L'utilisation de noms de revendication qui pourraient avoir des significations sémantiques contradictoires en dehors d'un système fermé ou privé est sujette à une collision, alors utilisez-les avec prudence.
Il est important de noter que nous voulons garder un jeton Web aussi petit que possible, donc utilisez uniquement les données nécessaires dans les revendications publiques et privées.
Exemple de charge utile JWT
{ 'iss': 'toptal.com', 'exp': 1426420800, 'https://www.toptal.com/jwt_claims/is_admin': true, 'company': 'ApeeScape', 'awesome': true }
Cet exemple de charge utile a deux revendications enregistrées, une revendication publique et deux revendications privées. Une fois qu'il est encodé en base64, nous avons la deuxième partie de notre JWT.
eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0
La norme JWT suit la spécification JSON Web Signature (JWS) pour générer le jeton signé final. Il est généré en combinant l'en-tête JWT codé et la charge utile JWT codée, et en le signant à l'aide d'un algorithme de cryptage fort, tel que HMAC SHA-256. La clé secrète de la signature est détenue par le serveur afin qu'il puisse vérifier les jetons existants et en signer de nouveaux.
$encodedContent = base64UrlEncode(header) + '.' + base64UrlEncode(payload); $signature = hashHmacSHA256($encodedContent);
Cela nous donne la dernière partie de notre JWT.
yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
Il est essentiel d'utiliser TLS / SSL en conjonction avec JWT, pour éviter les attaques de type 'man-in-the-middle'. Dans la plupart des cas, cela sera suffisant pour crypter la charge utile JWT si elle contient des informations sensibles. Cependant, si nous voulons ajouter une couche de protection supplémentaire, nous pouvons chiffrer la charge utile JWT elle-même à l'aide du Chiffrement Web JSON (PLAY) spécification.
Bien sûr, si nous voulons éviter la surcharge supplémentaire liée à l'utilisation de JWE, une autre option consiste simplement à conserver les informations sensibles dans notre base de données et à utiliser notre jeton pour des appels d'API supplémentaires au serveur chaque fois que nous avons besoin d'accéder à des données sensibles.
Avant de voir tous les avantages de l'utilisation de l'authentification JWT, nous devons examiner la façon dont l'authentification a été effectuée dans le passé.
Étant donné que le protocole HTTP est sans état, il doit y avoir un mécanisme pour stocker les informations utilisateur et un moyen d'authentifier l'utilisateur à chaque demande ultérieure après la connexion. La plupart des sites Web utilisent des cookies pour stocker l'identifiant de session de l'utilisateur.
Comment ça fonctionne
Le navigateur envoie une requête POST au serveur contenant l’identification et le mot de passe de l’utilisateur. Le serveur répond avec un cookie, qui est défini sur le navigateur de l'utilisateur, et comprend un identifiant de session pour identifier l'utilisateur.
À chaque demande suivante, le serveur doit trouver cette session et la désérialiser, car les données utilisateur sont stockées sur le serveur.
Difficile à mettre à l'échelle : Le serveur doit créer une session pour un utilisateur et la conserver quelque part sur le serveur. Cela peut être fait en mémoire ou dans une base de données. Si nous avons un système distribué, nous devons nous assurer que nous utilisons un stockage de session séparé qui n'est pas couplé au serveur d'applications.
Partage de demande cross-origin (CORS) : Lors de l'utilisation d'appels AJAX pour récupérer une ressource d'un autre domaine ('cross-origin'), nous pourrions rencontrer des problèmes avec les requêtes interdites car, par défaut, les requêtes HTTP n'incluent pas de cookies sur les requêtes cross-origin.
Couplage avec le framework web : Lors de l'utilisation de l'authentification basée sur le serveur, nous sommes liés au schéma d'authentification de notre framework. Il est vraiment difficile, voire impossible, de partager des données de session entre différents frameworks Web écrits dans différents langages de programmation.
L'authentification basée sur les jetons / JWT est sans état, il n'est donc pas nécessaire de stocker les informations utilisateur dans la session. Cela nous donne la possibilité de faire évoluer notre application sans nous soucier de l'endroit où l'utilisateur s'est connecté. Nous pouvons facilement utiliser le même jeton pour récupérer une ressource sécurisée à partir d'un domaine autre que celui auquel nous sommes connectés.
Fonctionnement des jetons Web JSON
Un navigateur ou un client mobile envoie une demande au serveur d'authentification contenant les informations de connexion de l'utilisateur. Le serveur d'authentification génère un nouveau jeton d'accès JWT et le renvoie au client. A chaque demande à une ressource restreinte, le client envoie le jeton d'accès dans la chaîne de requête ou Authorization
entête. Le serveur valide ensuite le jeton et, s'il est valide, renvoie la ressource sécurisée au client.
Le serveur d'authentification peut signer le jeton à l'aide de n'importe quelle méthode de signature sécurisée. Par exemple, un algorithme de clé symétrique tel que HMAC SHA-256 peut être utilisé s'il existe un canal sécurisé pour partager la clé secrète entre toutes les parties. Alternativement, un système asymétrique à clé publique, tel que RSA, peut également être utilisé, éliminant ainsi le besoin d'un partage de clé supplémentaire.
Apatride, plus facile à mettre à l'échelle : Le jeton contient toutes les informations permettant d'identifier l'utilisateur, éliminant ainsi le besoin de l'état de session. Si nous utilisons un équilibreur de charge, nous pouvons transmettre l'utilisateur à n'importe quel serveur, au lieu d'être lié au même serveur sur lequel nous nous sommes connectés.
Réutilisabilité : Nous pouvons avoir de nombreux serveurs distincts, fonctionnant sur plusieurs plates-formes et domaines, réutilisant le même jeton pour authentifier l'utilisateur. Il est facile de créer une application qui partage des autorisations avec une autre application.
Sécurité JWT : Étant donné que nous n'utilisons pas de cookies, nous n'avons pas à nous protéger contre les attaques de falsification de requêtes intersites (CSRF). Nous devons toujours crypter nos jetons en utilisant JWE si nous devons y mettre des informations sensibles, et transmettre nos jetons via HTTPS pour empêcher les attaques de type 'man-in-the-middle'.
Performance : Il n'y a pas de recherche côté serveur pour trouver et désérialiser la session à chaque requête. La seule chose que nous devons faire est de calculer le HMAC SHA-256 pour valider le jeton et analyser son contenu.
exemples de sites Web bootstrap avec code
Dans ce didacticiel JWT, je vais montrer comment implémenter l'authentification de base à l'aide de jetons Web JSON dans deux technologies Web populaires: Laravel 5 pour le code backend et AngularJS pour l'exemple de l'application frontale à page unique (SPA). (Vous pouvez trouver la démo entière Ici , et le code source dans ce référentiel GitHub afin que vous puissiez suivre le tutoriel.)
Cet exemple de jeton Web JSON n'utilisera aucun type de cryptage pour garantir la confidentialité des informations transmises dans les revendications. En pratique, cela est souvent correct, car TLS / SSL crypte la demande. Cependant, si le jeton doit contenir des informations sensibles, telles que le numéro de sécurité sociale de l'utilisateur, il doit également être chiffré à l'aide de JWE.
Nous utiliserons Laravel pour gérer l'enregistrement des utilisateurs, conserver les données utilisateur dans une base de données et fournir des données restreintes nécessitant une authentification pour que l'application Angular les consomme. Nous allons créer un exemple de sous-domaine d'API pour simuler également le partage de ressources cross-origin (CORS).
Installation et démarrage du projet
Pour utiliser Laravel, nous devons installer le Compositeur gestionnaire de paquets sur notre machine. Lors du développement à Laravel, je recommande d'utiliser la «boîte» préemballée de Laravel Homestead de Vagrant. Il nous fournit un environnement de développement complet quel que soit notre système d'exploitation.
Le moyen le plus simple de démarrer notre application JWT Laravel est d'utiliser un package Composer Laravel Installer.
composer global require 'laravel/installer=~1.1'
Nous sommes maintenant tous prêts à créer un nouveau projet Laravel en exécutant laravel new jwt
.
Pour toute question concernant ce processus, veuillez vous référer au site officiel Documentation Laravel .
Après avoir créé l'application de base Laravel 5, nous devons configurer notre Homestead.yaml
, qui configurera les mappages de dossiers et la configuration des domaines pour notre environnement local.
Exemple de Homestead.yaml
fichier:
--- ip: '192.168.10.10' memory: 2048 cpus: 1 authorize: /Users/ttkalec/.ssh/public.psk keys: - /Users/ttkalec/.ssh/private.ppk folders: - map: /coding/jwt to: /home/vagrant/coding/jwt sites: - map: jwt.dev to: /home/vagrant/coding/jwt/public - map: api.jwt.dev to: /home/vagrant/coding/jwt/public variables: - key: APP_ENV value: local
Après avoir démarré notre boîte Vagrant avec le vagrant up
et connecté en utilisant vagrant ssh
, nous naviguons vers le répertoire de projet précédemment défini. Dans l'exemple ci-dessus, ce serait /home/vagrant/coding/jwt
. Nous pouvons maintenant exécuter php artisan migrate
afin de créer les tables utilisateur nécessaires dans notre base de données.
Installation des dépendances de Composer
Heureusement, il existe une communauté de développeurs travaillant sur Laravel et gérant de nombreux packages formidables avec lesquels nous pouvons réutiliser et étendre notre application. Dans cet exemple, nous utiliserons tymon/jwt-auth
, par Sean Tymon, pour la gestion des jetons côté serveur, et barryvdh/laravel-cors
, par Barry vd. Heuvel, pour la manipulation de CORS.
jwt-auth
Exiger le tymon/jwt-auth
package dans notre composer.json
et mettre à jour nos dépendances.
composer require tymon/jwt-auth 0.5.*
Ajoutez le JWTAuthServiceProvider
à notre app/config/app.php
tableau des fournisseurs.
'TymonJWTAuthProvidersJWTAuthServiceProvider'
Ensuite, dans app/config/app.php
fichier, sous le aliases
tableau, nous ajoutons le JWTAuth
façade.
'JWTAuth' => 'TymonJWTAuthFacadesJWTAuth'
Enfin, nous voudrons publier la configuration du package en utilisant la commande suivante: php artisan config: publish tymon / jwt-auth
Les jetons Web JSON sont chiffrés à l'aide d'une clé secrète. Nous pouvons générer cette clé en utilisant le php artisan jwt:generate
commander. Il sera placé dans notre config/jwt.php
fichier. Dans l'environnement de production, cependant, nous ne voulons jamais avoir nos mots de passe ou clés API dans les fichiers de configuration. Au lieu de cela, nous devons les placer dans les variables d'environnement du serveur et les référencer dans le fichier de configuration avec env
fonction. Par exemple:
'secret' => env('JWT_SECRET')
Nous pouvons en savoir plus sur ce package et tous ses paramètres de configuration sur Github .
laravel-cors
Exiger le barryvdh/laravel-cors
package dans notre composer.json
et mettre à jour nos dépendances.
composer require barryvdh/laravel-cors [email protected]
Ajoutez le CorsServiceProvider
à notre app/config/app.php
tableau des fournisseurs.
'BarryvdhCorsCorsServiceProvider'
Ajoutez ensuite le middleware à notre app/Http/Kernel.php
.
'BarryvdhCorsMiddlewareHandleCors'
Publiez la configuration dans un local config/cors.php
fichier en utilisant le php artisan vendor:publish
commander.
Exemple de cors.php
configuration du fichier:
return [ 'defaults' => [ 'supportsCredentials' => false, 'allowedOrigins' => [], 'allowedHeaders' => [], 'allowedMethods' => [], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [], ], 'paths' => [ 'v1/*' => [ 'allowedOrigins' => ['*'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['*'], 'maxAge' => 3600, ], ], ];
Routage et traitement des requêtes HTTP
Par souci de brièveté, je vais mettre tout mon code dans le fichier routes.php qui est responsable du routage Laravel et de la délégation des requêtes aux contrôleurs. Nous créons généralement des contrôleurs dédiés pour gérer toutes nos requêtes HTTP et garder notre code modulaire et propre.
Nous chargerons notre vue AngularJS SPA en utilisant
Route::get('/', function () { return view('spa'); });
Enregistrement de l'utilisateur
Quand on fait un POST
demande à /signup
avec un nom d'utilisateur et un mot de passe, nous essaierons de créer un nouvel utilisateur et de l'enregistrer dans la base de données. Une fois l'utilisateur créé, un JWT est créé et renvoyé via une réponse JSON.
Route::post('/signup', function () { $credentials = Input::only('email', 'password'); try { $user = User::create($credentials); } catch (Exception $e) { return Response::json(['error' => 'User already exists.'], HttpResponse::HTTP_CONFLICT); } $token = JWTAuth::fromUser($user); return Response::json(compact('token')); });
Connexion utilisateur
Quand on fait un POST
demande à /signin
avec un nom d'utilisateur et un mot de passe, nous vérifions que l'utilisateur existe et renvoie un JWT via la réponse JSON.
Route::post('/signin', function () { $credentials = Input::only('email', 'password'); if ( ! $token = JWTAuth::attempt($credentials)) { return Response::json(false, HttpResponse::HTTP_UNAUTHORIZED); } return Response::json(compact('token')); });
Récupération d'une ressource restreinte sur le même domaine
Une fois que l'utilisateur est connecté, nous pouvons récupérer la ressource restreinte. J'ai créé un itinéraire /restricted
qui simule une ressource nécessitant un utilisateur authentifié. Pour ce faire, la requête Authorization
L'en-tête ou la chaîne de requête doit fournir le JWT que le backend doit vérifier.
Route::get('/restricted', [ 'before' => 'jwt-auth', function () { $token = JWTAuth::getToken(); $user = JWTAuth::toUser($token); return Response::json([ 'data' => [ 'email' => $user->email, 'registered_at' => $user->created_at->toDateTimeString() ] ]); } ]);
Dans cet exemple, j'utilise le jwt-auth
middleware fourni dans le jwt-auth
package utilisant 'before' => 'jwt-auth'
. Ce middleware est utilisé pour filtrer la demande et valider le jeton JWT. Si le jeton n'est pas valide, n'est pas présent ou a expiré, le middleware lèvera une exception que nous pouvons intercepter.
Dans Laravel 5, nous pouvons intercepter les exceptions en utilisant le app/Exceptions/Handler.php
fichier. Utilisation de render
fonction, nous pouvons créer des réponses HTTP en fonction de l'exception levée.
public function render($request, Exception $e) { if ($e instanceof TymonJWTAuthExceptionsTokenInvalidException) { return response(['Token is invalid'], 401); } if ($e instanceof TymonJWTAuthExceptionsTokenExpiredException) { return response(['Token has expired'], 401); } return parent::render($request, $e); }
Si l'utilisateur est authentifié et que le jeton est valide, nous pouvons renvoyer en toute sécurité les données restreintes au frontend via JSON.
Récupération des ressources restreintes à partir du sous-domaine API
Dans le prochain exemple de jeton Web JSON, nous adopterons une approche différente pour la validation des jetons. Au lieu d'utiliser jwt-auth
middleware, nous traiterons les exceptions manuellement. Quand on fait un POST
demande à un serveur d'API api.jwt.dev/v1/restricted
, nous faisons une demande cross-origin et devons activer CORS sur le backend. Heureusement, nous avons déjà configuré CORS dans le config/cors.php
fichier.
Route::group(['domain' => 'api.jwt.dev', 'prefix' => 'v1'], function () { Route::get('/restricted', function () { try { JWTAuth::parseToken()->toUser(); } catch (Exception $e) { return Response::json(['error' => $e->getMessage()], HttpResponse::HTTP_UNAUTHORIZED); } return ['data' => 'This has come from a dedicated API subdomain with restricted access.']; }); });
Nous utilisons AngularJS en tant que frontal, en nous appuyant sur les appels d'API au serveur d'authentification principal Laravel pour l'authentification des utilisateurs et les exemples de données, ainsi que sur le serveur API pour les données d'exemple d'origine croisée. Une fois que nous allons à la page d'accueil de notre projet, le backend servira le resources/views/spa.blade.php
vue qui démarrera l'application Angular.
Voici la structure des dossiers de l'application Angular:
public/ |-- css/ `-- bootstrap.superhero.min.css |-- lib/ |-- loading-bar.css |-- loading-bar.js `-- ngStorage.js |-- partials/ |-- home.html |-- restricted.html |-- signin.html `-- signup.html `-- scripts/ |-- app.js |-- controllers.js `-- services.js
Amorcer l'application angulaire
spa.blade.php
contient le strict nécessaire pour exécuter l'application. Nous utiliserons Twitter Bootstrap pour le style, ainsi qu'un thème personnalisé de Botteswatch . Pour avoir des commentaires visuels lors d'un appel AJAX, nous allons utiliser le barre de chargement angulaire script, qui intercepte les requêtes XHR et crée une barre de chargement. Dans la section d'en-tête, nous avons les feuilles de style suivantes:
ngStorage
Le pied de page de notre balisage contient des références à des bibliothèques, ainsi que nos scripts personnalisés pour les modules angulaires, les contrôleurs et les services.
Authorization
Nous utilisons token
bibliothèque pour AngularJS, pour enregistrer les jetons dans le stockage local du navigateur, afin que nous puissions l'envoyer à chaque demande via le Toggle navigation JWT Angular example
entête.
Dans l'environnement de production, bien sûr, nous réduisions et combinions tous nos fichiers de script et feuilles de style afin d'améliorer les performances.
J'ai créé une barre de navigation à l'aide de Bootstrap qui modifiera la visibilité des liens appropriés, en fonction de l'état de connexion de l'utilisateur. L'état de connexion est déterminé par la présence d'un app.js
variable dans la portée du contrôleur.
angular.module('app', [ 'ngStorage', 'ngRoute', 'angular-loading-bar' ]) .constant('urls', { BASE: 'http://jwt.dev:8000', BASE_API: 'http://api.jwt.dev:8000/v1' }) .config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) { $routeProvider. when('/', { templateUrl: 'partials/home.html', controller: 'HomeController' }). when('/signin', { templateUrl: 'partials/signin.html', controller: 'HomeController' }). when('/signup', { templateUrl: 'partials/signup.html', controller: 'HomeController' }). when('/restricted', { templateUrl: 'partials/restricted.html', controller: 'RestrictedController' }). otherwise({ redirectTo: '/' });
Routage
Nous avons un fichier nommé HomeController
qui est responsable de la configuration de toutes nos routes frontales.
RestrictedController
Ici, nous pouvons voir que nous avons défini quatre routes qui sont gérées par Authorization
ou $httpProvider.interceptors.push(['$q', '$location', '$localStorage', function ($q, $location, $localStorage) { return { 'request': function (config) { config.headers = config.headers || {}; if ($localStorage.token) { config.headers.Authorization = 'Bearer ' + $localStorage.token; } return config; }, 'responseError': function (response) { if (response.status === 401 || response.status === 403) { $location.path('/signin'); } return $q.reject(response); } }; }]);
. Chaque itinéraire correspond à une vue HTML partielle. Nous avons également défini deux constantes contenant des URL pour nos requêtes HTTP vers le backend.
Demander un intercepteur
Le service $ http d'AngularJS nous permet de communiquer avec le backend et de faire des requêtes HTTP. Dans notre cas, nous voulons intercepter chaque requête HTTP et l'injecter avec un controllers.js
en-tête contenant notre JWT si l'utilisateur est authentifié. Nous pouvons également utiliser un intercepteur pour créer un gestionnaire d'erreur HTTP global. Voici un exemple de notre intercepteur qui injecte un jeton s'il est disponible dans le stockage local du navigateur.
HomeController
Contrôleurs
Dans le RestrictedController
fichier, nous avons défini deux contrôleurs pour notre application: HomeController
et Auth
. angular.module('app') .controller('HomeController', ['$rootScope', '$scope', '$location', '$localStorage', 'Auth', function ($rootScope, $scope, $location, $localStorage, Auth) { function successAuth(res) { $localStorage.token = res.token; window.location = '/'; } $scope.signin = function () { var formData = { email: $scope.email, password: $scope.password }; Auth.signin(formData, successAuth, function () { $rootScope.error = 'Invalid credentials.'; }) }; $scope.signup = function () { var formData = { email: $scope.email, password: $scope.password }; Auth.signup(formData, successAuth, function () { $rootScope.error = 'Failed to signup'; }) }; $scope.logout = function () { Auth.logout(function () { window.location = '/' }); }; $scope.token = $localStorage.token; $scope.tokenClaims = Auth.getTokenClaims(); }])
gère les fonctionnalités de connexion, d'inscription et de déconnexion. Il transmet les données de nom d'utilisateur et de mot de passe des formulaires de connexion et d'inscription à RestrictedController
service, qui envoie des requêtes HTTP au backend. Il enregistre ensuite le jeton dans le stockage local ou affiche un message d'erreur, en fonction de la réponse du backend.
getRestrictedData
getApiData
se comporte de la même manière, mais il récupère les données en utilisant le Data
et .controller('RestrictedController', ['$rootScope', '$scope', 'Data', function ($rootScope, $scope, Data) { Data.getRestrictedData(function (res) { $scope.data = res.data; }, function () { $rootScope.error = 'Failed to fetch restricted content.'; }); Data.getApiData(function (res) { $scope.api = res.data; }, function () { $rootScope.error = 'Failed to fetch restricted API content.'; }); }]);
fonctions sur le Authorization
un service.
tokenClaims
Le backend est responsable de la diffusion des données restreintes uniquement si l'utilisateur est authentifié. Cela signifie que pour répondre avec les données restreintes, la demande de ces données doit contenir un JWT valide dans son getTokenClaims
en-tête ou chaîne de requête. Si ce n'est pas le cas, le serveur répondra avec un code d'état d'erreur 401 Non autorisé.
Service d'authentification
Le service Auth est responsable de la connexion et de l'inscription des requêtes HTTP au backend. Si la demande aboutit, la réponse contient le jeton signé, qui est ensuite décodé en base64, et les informations de réclamation de jeton jointes sont enregistrées dans un angular.module('app') .factory('Auth', ['$http', '$localStorage', 'urls', function ($http, $localStorage, urls) { function urlBase64Decode(str) { var output = str.replace('-', '+').replace('_', '/'); switch (output.length % 4) { case 0: break; case 2: output += '=='; break; case 3: output += '='; break; default: throw 'Illegal base64url string!'; } return window.atob(output); } function getClaimsFromToken() { var token = $localStorage.token; var user = {}; if (typeof token !== 'undefined') { var encoded = token.split('.')[1]; user = JSON.parse(urlBase64Decode(encoded)); } return user; } var tokenClaims = getClaimsFromToken(); return { signup: function (data, success, error) { $http.post(urls.BASE + '/signup', data).success(success).error(error) }, signin: function (data, success, error) { $http.post(urls.BASE + '/signin', data).success(success).error(error) }, logout: function (success) { tokenClaims = {}; delete $localStorage.token; success(); }, getTokenClaims: function () { return tokenClaims; } }; } ]);
variable. Ceci est transmis au contrôleur via le angular.module('app') .factory('Data', ['$http', 'urls', function ($http, urls) { return { getRestrictedData: function (success, error) { $http.get(urls.BASE + '/restricted').success(success).error(error) }, getApiData: function (success, error) { $http.get(urls.BASE_API + '/restricted').success(success).error(error) } }; } ]);
fonction.
|_+_|
Service de données
Il s'agit d'un service simple qui envoie des requêtes au serveur d'authentification ainsi qu'au serveur API pour certaines données restreintes factices. Il effectue la demande et délègue les rappels de réussite et d'erreur au contrôleur.
|_+_|
L'authentification basée sur les jetons nous permet de construire des systèmes découplés qui ne sont pas liés à un schéma d'authentification particulier. Le jeton peut être généré n'importe où et utilisé sur n'importe quel système qui utilise la même clé secrète pour signer le jeton. Ils sont prêts pour les appareils mobiles et ne nous obligent pas à utiliser des cookies.
Les jetons Web JSON fonctionnent dans tous les langages de programmation populaires et gagnent rapidement en popularité. Ils sont soutenus par des entreprises comme Google, Microsoft et Zendesk. Leur spécification standard par Internet Engineering Task Force (IETF) est toujours dans la version provisoire et peut changer légèrement à l'avenir.
Il y a encore beaucoup à couvrir sur les JWT, comme la façon de gérer Sécurité détails et actualisation des jetons lorsqu'ils expirent, mais le didacticiel sur les jetons Web JSON doit démontrer l'utilisation de base et, plus important encore, les avantages de l'utilisation des JWT.
Cela fait référence à un JWT, qui est transmis via l'en-tête HTTP appelé Authorization, dans le format de chaîne 'Bearer $ your_token_here'.
JWT signifie JSON Web Token, une tactique d'authentification courante utilisée dans les applications Web modernes.
JSON est simplement un format de données qui ressemble étroitement au format littéral de données autorisé par JavaScript. C'est un format hiérarchique permettant des objets et des tableaux imbriqués, ainsi que des littéraux de chaîne et de nombre.