Exemple de jeton dauthentification asp net core api

Précédent : Tutoriels sur l’API Web ASP.NET Core

Authentification JWT dans l’API Web ASP.NET Core

Dans cet article, je vais voir comment implémenter l’authentification basée sur les jetons à l’aide de JWT dans ASP.NET application API Web principale. Veuillez lire notre article précédent sur l’authentification de base basée sur les rôles dans ASP.NET API Web de base . À la fin de cet article, vous comprendrez les points suivants :

  1. Pourquoi avons-nous besoin d’une authentification basée sur des jetons dans ASP.NET API Web de base ?
  2. Qu’est-ce que l’authentification basée sur les jetons ?
  3. Qu’est-ce que l’authentification JWT et ses composants ?
  4. Comment fonctionne l’authentification JWT dans ASP.NET API Web de base ?
  5. Création du serveur d’authentification Application pour générer un jeton JWT Création d’une
  6. API Application de serveur de ressources avec validation de jeton JWT
  7. Création d’applications clientes pour consommer les services du serveur de ressources avec l’authentification JWT
  8. Avantages et inconvénients de l’utilisation de l’authentification basée sur un jeton dans ASP.NET’API
Web de base Pourquoi avons-nous besoin d’une authentification basée sur des jetons dans ASP.NET API Web de base ?

L’API Web ASP.NET Core est un cadre idéal fourni par Microsoft pour créer des API Web, c’est-à-dire des services basés sur HTTP au-dessus du .NET Core Framework. Une fois que nous aurons développé les services d’API Web, ces services seront consommés par un large éventail de clients, tels que

les
  • navigateurs, les
  • applications mobiles
  • , les
  • applications de bureau
  • , les IOT, etc.

De nos jours, l’utilisation des API Web augmente rapidement. Il faut donc savoir développer des API Web. Cependant, le développement d’API Web ne suffit pas seul s’il n’y a pas de sécurité. Par conséquent, il est également important pour nous de mettre en œuvre la sécurité de nos services d’API Web, qui seront consommés par différents clients, tels que les navigateurs, les appareils mobiles, les applications de bureau et les IoTs.

De nos jours, l’approche la plus privilégiée pour sécuriser les ressources de l’API Web consiste à authentifier les utilisateurs sur le serveur d’API Web à l’aide du jeton signé (qui contient suffisamment d’informations pour identifier un utilisateur particulier), qui doit être envoyé au serveur par le client à chaque demande. C’est ce qu’on appelle l’approche d’authentification basée sur les jetons.

Qu’est-ce que l’authentification basée sur les jetons ?

Dans ASP.NET API Web de base, l’authentification basée sur des jetons est une méthode populaire pour sécuriser les API Web en validant la Identité des utilisateurs via des tokens. Cette méthode est préférée dans de nombreuses applications Web modernes en raison de son absence d’état, ce qui s’aligne bien avec la nature sans état de HTTP. Voici les étapes ou le processus de fonctionnement de l’authentification basée sur des jetons :

  • Connexion utilisateur : le client envoie une demande à un point de terminaison d’authentification avec des informations d’identification (comme le nom d’utilisateur et le mot de passe). Le serveur valide ces informations d’identification par rapport à une base de données ou à un autre fournisseur d’authentification.
  • Génération de jetons : une fois l’authentification réussie, le serveur génère un jeton. Ce jeton contient des informations essentielles (revendications) sur l’utilisateur, telles que l’ID utilisateur, le nom d’utilisateur, l’adresse e-mail, les rôles et le délai d’expiration du jeton. Le type de jeton le plus courant est le jeton Web JSON (JWT).
  • Jeton envoyé au client : Le serveur renvoie ensuite le jeton au client, qui doit Stockez-les en toute sécurité (généralement dans le stockage local ou le stockage de session).
  • Demandes du client avec jeton : pour les demandes ultérieures de sécurisation des points de terminaison, le client doit inclure ce jeton, généralement dans l’en-tête Authorization avec un schéma de porteur. Par exemple, Autorisation : Porteur <jeton > .
  • Validation du jeton de serveur : lorsque le serveur reçoit une demande avec un jeton, il valide d’abord le jeton. Cette validation peut impliquer la vérification de la signature du jeton, s’assurer qu’il n’a pas expiré et vérifier toutes les revendications incluses.
  • Accès accordé ou refusé : le serveur traite la demande une fois le jeton validé. Si le jeton n’est pas valide (par exemple, expiré ou altéré), le serveur rejette la demande, généralement avec une réponse 401 non autorisée, et le client peut devoir s’authentifier à nouveau pour obtenir un nouveau jeton. Le serveur peut également utiliser Les revendications du jeton pour effectuer une autorisation, comme autoriser l’accès à certaines méthodes en fonction des rôles d’utilisateur.
  • Expiration et renouvellement des jetons : Les jetons ont généralement une date d’expiration. Lorsqu’un jeton expire, il peut être renouvelé (c’est-à-dire en actualisant le jeton) ou l’utilisateur peut avoir besoin de s’authentifier à nouveau pour en recevoir un nouveau.
Qu’est-ce que l’authentification JWT et quels sont ses composants dans ASP.NET API Web de base ?

JWT est l’abréviation de JSON Web Token. Il permet la transmission sécurisée d’informations sous la forme d’un objet JSON signé numériquement (à l’aide d’un secret ou d’une paire de clés publique/privée) et chiffré. Les JWT sont couramment utilisés pour l’authentification et l’échange d’informations dans les services Web Restful. Un JWT se compose de trois composants principaux :

En-tête JWT :

L’en-tête JWT contient des métadonnées sur le type de jeton et les algorithmes cryptographiques utilisés. L’en-tête se compose généralement de deux parties : le type du jeton, qui est JWT, et l’algorithme de signature utilisé, tel que HMACSHA256 ou RSA. Cela ressemble à quelque chose comme ceci :

{ « alg » : « HS256 », « typ » : « JWT » }

Ce JSON est alors encodé en Base64Url pour former la première partie du JWT.

Charge utile JWT :

La charge utile de JWT (JSON Web Token) est la partie très importante où la majeure partie des données est stockée. Il se compose d’un ensemble de revendications, qui sont des déclarations concernant une entité (généralement un utilisateur) et d’autres données. La charge utile est représentée sous la forme d’un objet JSON et peut inclure trois types de revendications : les revendications enregistrées, publiques et privées.

Réclamations enregistrées : Il s’agit d’un ensemble prédéfini de réclamations qui ne sont pas obligatoires, mais qui sont recommandées pour fournir un ensemble de réclamations utiles. Il s’agit de standardisé et fournir un moyen cohérent d’accéder aux informations importantes sur le jeton. Voici quelques-unes des créances enregistrées courantes :

  • iss (émetteur) : Cette revendication identifie le principal qui a émis le JWT. Par exemple, il peut s’agir du nom de domaine du service d’authentification.
  • sub (Objet) : Cette revendication identifie le principal qui fait l’objet du JWT, souvent un ID utilisateur ou un nom d’utilisateur que ce jeton représente.
  • aud (Audience) : Cette revendication identifie les destinataires auxquels le JWT est destiné. Il peut s’agir du nom de domaine de l’application cliente.
  • exp (Délai d’expiration) : cette revendication de date numérique définit le délai d’expiration du JWT ou après cette date. Il est généralement représenté en temps Unix (également connu sous le nom de temps Epoch).
  • nbf (pas Avant) : à l’instar de exp, cette revendication de date numérique définit le délai avant lequel le JWT ne doit pas être accepté pour le traitement.
  • iat (Issued At) : Cette revendication de date numérique enregistre l’heure à laquelle le JWT a été émis, également en temps Unix.
  • jti (JWT ID) : Cette revendication fournit un identifiant unique pour le JWT. Il peut être utilisé pour empêcher le JWT d’être rejoué.

Créances publiques : Il s’agit des créances qui ne sont pas enregistrées, mais qui ne sont pas non plus privées. Ils peuvent être utilisés pour partager des informations entre les parties qui acceptent de les utiliser et sont généralement définis dans un espace de noms qui empêche les collisions avec d’autres revendications. Il peut s’agir, par exemple, d’une revendication détaillant les autorisations ou les rôles de l’utilisateur, comme « role » : « admin ».

Revendications privées : il s’agit de revendications personnalisées créées pour partager des informations entre parties qui acceptent de les utiliser et qui ne sont ni des créances enregistrées ni publiques. Par exemple, une application peut inclure des revendications liées aux niveaux d’accès des utilisateurs ou aux données de profil, comme « pseudo » : « johnny123 ».

Exemple d’une charge utile JWT :
{ « iss » : « http://example.com », « sub » : « user12345 », « aud » : « http://exampleapp.com », « exp » : 1700001234, « nbf » : 1699990000, « iat » : 1699990200, « jti » : « uniqueid123 », « role » : « admin », « nickname » : « johnny123 » }

Ce JSON est également encodé en Base64Url pour former la deuxième partie du JWT.

Signature JWT :

la signature de JWT est utilisée pour vérifier que l’expéditeur du JWT est bien celui qu’il prétend être et pour s’assurer que le message n’a pas été modifié en cours de route. Pour créer la partie signature, vous devez prendre L’en-tête codé, la charge utile codée, un secret et l’algorithme spécifié dans l’en-tête. Par exemple, si vous utilisez l’algorithme HMAC SHA256, la signature sera créée comme suit :

HMACSHA256( base64UrlEncode(header) + « . » + base64UrlEncode(payload), secret)

La signature est la troisième partie du JWT.

En résumé :

le résultat est constitué de trois chaînes d’URL Base64 séparées par des points. La structure ressemble à ceci :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  1. La première partie est l’en-tête encodé en Base64Url.
  2. La deuxième partie est la charge utile encodée en Base64Url.
  3. La troisième partie est la signature encodée en Base64Url.

Ce form permet d’envoyer des JWT via des paramètres d’URL, des en-têtes HTTP ou dans un corps HTTP. Le destinataire décode le JWT pour revendiquer le jeton et vérifier la signature à des fins de sécurité.

Comment fonctionne l’authentification JWT dans ASP.NET API Web de base ?

L’authentification JWT (JSON Web Tokens) dans ASP.NET API Web Core implique l’utilisation de jetons pour sécuriser la communication entre un client, un serveur d’autorisation et un serveur de ressources. Ce mécanisme d’authentification est utile dans les scénarios où nous devons implémenter l’authentification sans état dans un système distribué. Les composants suivants impliqués dans l’authentification par jeton basée sur JWT dans ASP.NET API Web principale :

  • Client : l’entité qui demande l’accès aux ressources.
  • Serveur d’autorisation : valide les informations d’identification fournies par le client et émet des jetons.
  • Serveur de ressources : Ce serveur héberge les ressources protégées et utilise le jeton envoyé par le client pour authentifier et autoriser les demandes.

Pour mieux comprendre comment cela fonctionne dans ASP.NET API Web principale, veuillez consulter le schéma suivant :

Authentification sur le serveur d’autorisation

Le client envoie une demande de connexion avec des informations d’identification (nom d’utilisateur et mot de passe) au serveur d’autorisation. Si les informations d’identification sont valides, le serveur d’autorisation génère un JWT. Ce jeton comprend des revendications sur l’utilisateur et des données supplémentaires nécessaires à l’autorisation, telles que les rôles ou les autorisations de l’utilisateur. Le serveur d’autorisation signe le JWT à l’aide d’une clé secrète ou d’une paire de clés publique/privée. Le client reçoit ce jeton.

Utilisation du jeton sur le serveur de ressources

Le client effectue une demande au serveur de ressources pour les ressources et inclut le JWT dans l’en-tête d’autorisation HTTP. Le serveur de ressources valide la signature du jeton et vérifie la validité du jeton (expiration, émetteur, public visé, etc.). Si le jeton est valide, le serveur vérifie les revendications dans le jeton pour déterminer si le client dispose des autorisations nécessaires pour accéder aux ressources demandées. Poursuivons et implémentons la même étape par étape :

Création de l’application du serveur d’authentification

Le serveur d’authentification gérera l’authentification des utilisateurs et la génération de jetons. Par conséquent, créez un nouveau projet d’API Web Core ASP.NET nommé JWTAuthServer . Une fois que vous avez créé le projet, installez le package suivant :

Microsoft.AspNetCore.Authentication.JwtBearer

Vous pouvez installer le package à l’aide du Gestionnaire de package NuGet pour la solution ou en exécutant la commande suivante dans la console du gestionnaire de package :

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

Création du modèle utilisateur :

Maintenant, nous devons créer le modèle utilisateur, qui contiendra les informations de l’utilisateur. Par conséquent, créez un fichier de classe nommé User.cs dans le dossier Models, puis copiez et collez le code suivant :

namespace JWTAuthServer.Models { public class User { // Cette propriété représente l'identifiant unique de l'utilisateur dans la base de données. public int Id { get ; set ; } // Cette propriété est généralement utilisée comme identifiant unique à des fins de connexion. public string Username { get ; set ; } // Cette propriété stocke le mot de passe de l'utilisateur, qui doivent être hachés en toute sécurité avant d’être stockés. public string Password { get ; set ; } // Stocke l'adresse e-mail de l'utilisateur, utilisée pour la communication ou récupération de mot de passe. public string Email { get ; set ; } // Cette liste contient les rôles attribués à l’utilisateur, utilisés pour l’autorisation. Il est initialisé sous la forme d’une nouvelle liste de chaînes, ce qui signifie qu’il commence vide mais prêt à être ajouté. public List<string> Roles { get ; set ; } = new List<string>() ; Chaque

fois qu’un nouvel utilisateur s’inscrit à notre application, nous devons stocker les détails de l’utilisateur dans la base de données. Mais, pour plus de simplicité, créons une liste pour stocker tous les utilisateurs de notre application. Créez donc un fichier de classe nommé UserStore.cs dans le dossier Models, puis copiez et collez le code suivant.

namespace JWTAuthServer.Models { public class UserStore { // Déclare une liste statique publique d'objets User nommés 'Users'. // Étant statique, cette liste est partagée entre toutes les instances de la classe UserStore et accessible sans créer d'instance de la classe. // Cette liste est initialisée avec des données utilisateur prédéfinies. public static List<User> Users = new List<User> { new User { id=1, Username = « admin », Password = « password », Email="[email protected] », Roles = new List<string> { « admin », « User » } }, new User { id=2, Username = « user », password = « password », email="[email protected] », Roles = new List<string> { « User » } }, new User { id=3, Username = « test », Password = « password », Email="[email protected] », Roles = new List<string> { « Admin » } } } ; Création
d’un modèle de connexion :

Maintenant, nous devons créer un modèle qui doit accepter les détails de l’utilisateur (nom d’utilisateur et mot de passe), puis valider l’utilisateur et générer le jeton si le nom d’utilisateur et le mot de passe fournis sont valides. Créez donc un fichier de classe nommé Login.cs dans le dossier Models, puis copiez et collez le code suivant.

à l’aide de System.ComponentModel.DataAnnotations ; namespace JWTAuthServer.Models { public class Login { // Cette propriété représente le nom d’utilisateur saisi par un utilisateur pendant le processus de connexion. // Les noms d’utilisateur sont essentiels pour identifier l’utilisateur dans le système. // L’attribut Required garantit que le champ du nom d’utilisateur n’est pas vide. // L’attribut StringLength peut être utilisé pour spécifier la longueur maximale du nom d’utilisateur. [Required(ErrorMessage = « Le nom d’utilisateur est requis. »)] [StringLength(100, ErrorMessage = « Le nom d’utilisateur doit comporter moins de 100 caractères. »)] chaîne publique Nom d’utilisateur { get ; set ; } // Cette propriété est utilisée pour stocker le mot de passe saisi par un utilisateur pendant le processus de connexion. Les mots de passe doivent être gérés de manière sécurisée pour empêcher tout accès non autorisé. L’attribut Required garantit que le champ de mot de passe n’est pas laissé vide. L’attribut StringLength Peut spécifier des longueurs de mot de passe minimale et maximale, ce qui renforce la sécurité. [Required(ErrorMessage = « Le mot de passe est requis. »)] [StringLength(100, MinimumLength = 6, ErrorMessage = « Le mot de passe doit comporter entre 6 et 100 caractères. »)] chaîne publique Mot de passe { get ; set ; } } Création
d’un contrôleur API :

Créez un contrôleur qui authentifiera un utilisateur et émettra un JWT pris. Par conséquent, créez un contrôleur vide d’API nommé UsersController dans le dossier Controllers, puis copiez-collez-y le code suivant.

à l’aide de JWTAuthServer.Models ; à l’aide de Microsoft.AspNetCore.Mvc ; à l’aide de Microsoft.IdentityModel.Tokens ; à l’aide de System.IdentityModel.Tokens.Jwt ; en utilisant System.Security.Claims ; à l’aide de System.Text ; namespace JWTAuthServer.Controllers { [Route(« api/[controller] »)] [ApiController] public class AuthController : ControllerBase { // Champ privé pour contenir le paramètres de configuration injectés via le constructeur. privé en lecture seule IConfiguration _configuration ; Constructeur qui accepte IConfiguration et initialise le champ _configuration. public AuthController(IConfiguration configuration) { _configuration = configuration ; } // Méthode d’action répondant aux requêtes POST sur « api/Users/Login ». Attend un modèle Login dans le corps de la demande. [HttpPost(« Login »)] public IActionResult Login([FromBody] Demande de connexion) { // Vérifie si le modèle fourni (demande) est valide en fonction des annotations de données dans le modèle de connexion. if (ModelState.IsValid) { // Recherche un utilisateur dans un magasin d’utilisateurs prédéfini qui correspond à la fois au nom d’utilisateur et au mot de passe. var user = UserStore.Users.FirstOrDefault(u => u.Username == demande. Nom d’utilisateur & u.Mot de passe == demande. Mot de passe) ; Vérifie si l’objet utilisateur est nul, ce qui signifie qu’aucun utilisateur correspondant n’a été trouvé. if (user == null) { // Renvoie un 401 Non autorisé avec un message personnalisé. return Unauthorized(« Informations d’identification de l’utilisateur non valides. ») ; } // Appelle une méthode pour générer un jeton JWT pour l’utilisateur authentifié. var token = IssueToken(utilisateur) ; Renvoie une réponse 200 OK, encapsulant le jeton JWT dans un objet anonyme. return Ok(new { Token = token }) ; } // Si l’état du modèle n’est pas valide, renvoie une réponse 400 Bad Request avec un message personnalisé. return BadRequest(« Corps de la requête invalide ») ; } // Méthode privée pour générer un jeton JWT à partir des données de l'utilisateur. private string IssueToken(User user) { // Crée une nouvelle clé de sécurité symétrique à partir de la clé JWT spécifiée dans la configuration de l’application. var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt :Key"])) ; // Configure les identifiants de signature à l’aide de la clé de sécurité ci-dessus et en spécifiant l’algorithme HMAC SHA256. var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256) ; Définit un ensemble de revendications à inclure dans le jeton. var claims = new List<Claim> { // Revendication personnalisée à l'aide de l'ID de l'utilisateur. new Claim(« Myapp_User_Id », utilisateur. Id.ToString()), // Revendication standard pour l’identifiant de l’utilisateur, en utilisant le nom d’utilisateur. new Claim(ClaimTypes.NameIdentifier, utilisateur. Nom d'utilisateur), // Revendication standard pour l'adresse e-mail de l'utilisateur. new Claim(ClaimTypes.Email, utilisateur. Email), // Revendication JWT standard pour l’objet, à l’aide de l’ID utilisateur. new Claim(JwtRegisteredClaimNames.Sub, utilisateur. Id.ToString()) } ; Ajoute une revendication de rôle pour chaque rôle associé à l’utilisateur. utilisateur. Roles.ForEach(role => revendications. Ajouter(new Claim(ClaimsTypes.Role, role))) ; Crée un jeton JWT avec des paramètres spécifiés, notamment l’émetteur, l’audience, les revendications, le délai d’expiration et les informations d’identification de signature. var token = new JwtSecurityToken( émetteur : _configuration["Jwt :Émetteur"], audience : _configuration["Jwt :Audience"], claims : réclame, expire : DateTime.Now.AddHours(1), // Expiration du jeton définie à 1 heure à partir de l’heure actuelle. signingCredentials : références) ; Sérialise le jeton JWT en une chaîne et le renvoie. return new JwtSecurityTokenHandler(). WriteToken(jeton) ;

L’objectif principal de la méthode de connexion est d’authentifier les utilisateurs en fonction de leurs informations d’identification (nom d’utilisateur et mot de passe). Une fois l’authentification réussie, il génère et retourne un jeton JWT que le client peut utiliser pour les demandes d’API ultérieures afin de prouver son statut authentifié. Les opérations suivantes sont effectuées dans la méthode IssueToken pour générer un jeton JWT :

  • Recevoir les informations d’identification : la méthode accepte un modèle de connexion contenant les informations d’identification de l’utilisateur (nom d’utilisateur et mot de passe) via une requête POST.
  • Valider les informations d’identification : il valide les informations d’identification fournies par rapport à un magasin d’utilisateurs (par exemple, une base de données ou un magasin en mémoire).
  • Génération de jeton : si les informations d’identification sont valides, la méthode utilise la méthode IssueToken pour générer un JWT pour l’utilisateur authentifié.
  • Réponse : pour les utilisateurs authentifiés, il renvoie le jeton JWT dans le corps de la réponse. Si les informations d’identification ne sont pas valides ou si la validation échoue, il renvoie une réponse d’erreur (401 Non autorisé pour les informations d’identification non valides ou 400 Mauvaise demande pour les données d’entrée non valides).
Présentation de la méthode IssueToken

L’objectif de la méthode privée IssueToken est de générer un JWT pour un utilisateur qui s’est authentifié avec succès. Ce jeton sert de jeton d’accès permettant à l’utilisateur d’effectuer des appels d’API autorisés. Les opérations suivantes sont effectuées dans la méthode IssueToken pour générer un jeton JWT :

  • Sécurité Configuration de la clé : elle configure une clé de sécurité symétrique à partir d’une clé secrète définie dans la configuration de l’application.
  • Informations d’identification de signature : Établit les informations d’identification de signature à l’aide de la clé symétrique et de l’algorithme HMAC SHA256.
  • Définition des revendications : Rassemble un ensemble de revendications à inclure dans le JWT. Ces revendications contiennent généralement des informations d’identification de l’utilisateur, telles que l’ID utilisateur, le nom d’utilisateur et les rôles, qui sont essentielles pour autoriser les actions de l’utilisateur sur le serveur.
  • Création de jeton : cette fonction construit le JWT à l’aide des paramètres définis, tels que l’émetteur, l’audience, les revendications, le délai d’expiration et les informations d’identification de signature.
  • Sérialisation du jeton : sérialise le JWT sous forme de chaîne et le renvoie.
Modifier appsettings.json Fichier :

assurez-vous que les paramètres de l’émetteur, de l’audience et de la clé sont configurés dans votre fichier appsettings.json, qui est utilisé par le service d’authentification JWT dans la classe Program. Veuillez donc modifier le fichier appsettings.json comme suit :

{ « Logging » : { « LogLevel » : { « Default » : « Information », « Microsoft.AspNetCore » : « Avertissement » } }, « AllowedHosts » : « * », « Jwt » : { « Key » : « KHPK6Ucf/zjvU4qW8/vkuuGLHeIo0l9ACJiTaAPLKbk= », //Clé secrète « Issuer » : « https://localhost:7035 », //Adresse de base de l’URL du domaine du serveur d’authentification « Audience » : « http://localhost:5001 » //Adresse de base de l’URL du domaine de l’application cliente } }
Ignorer la casse Camel Convention de nommage :

Nous voulons que le nom de la propriété JSON soit affiché tel quel. Alors, modifiez le AddControllers comme suit dans le fichier de classe Program.cs :

builder. Services.AddControllers() . AddJsonOptions(options => { // Cette option utilisera les noms de propriété tels que définis dans les options du modèle C#. JsonSerializerOptions.PropertyNamingPolicy = null ; });
Création d’une application console pour la génération de la clé secrète :

créez une application console Dot Net, puis modifiez la classe Program comme suit pour générer la clé secrète. Le code suivant est auto-expliqué, veuillez donc lire les lignes de commentaires pour une meilleure compréhension.

en utilisant System.Security.Cryptography ; namespace KeyGeneratorApp { class Program { static void Main(string[] args) { // Allouer un tableau pour stocker des octets aléatoires. // Ce tableau a 32 octets, équivalent à 256 bits. var randomBytes = new byte[32] ; // Crée une instance d’un générateur de nombres aléatoires cryptographique. en utilisant (var rng = RandomNumberGenerator.Create()) { // Remplit le tableau précédemment défini avec des octets aléatoires générés en toute sécurité. rng. GetBytes(randomBytes) ; } // Le bloc 'using' garantit que l'objet RandomNumberGenerator est correctement éliminé après utilisation. Convertissez le tableau d’octets aléatoires en une chaîne Base64 pour le rendre lisible et facile à gérer en tant que texte. Console.WriteLine(Convert.ToBase64String(randomBytes)) ; Mettez le programme en pause et attendez que l’utilisateur appuie sur une touche pour pouvoir voir la sortie avant la fermeture de la fenêtre de la console. Console.ReadKey() ; Maintenant

, exécutez le code ci-dessus pour chaque client et obtenez la clé secrète.

Test de la génération de jeton JWT :

avec cela, notre implémentation du serveur d’authentification est terminée, qui validera les détails de l’utilisateur et générera le jeton JWT. Par conséquent, pour tester la fonctionnalité, exécutez l’application et accédez au point de terminaison de connexion à l’aide de n’importe quel outil client tel que Postman, Swagger ou Fiddler en fournissant le nom d’utilisateur et le mot de passe, et il devrait générer le jeton JWT comme indiqué dans l’image ci-dessous :

Comprendre le jeton généré :

Comme vous pouvez le voir, le jeton est généré en trois parties. Pour comprendre les différentes parties du jeton généré, veuillez consulter le site Web de l’https://jwt.io/. Remplacez votre jeton généré dans la section Codé, et vous devriez voir les différentes parties dans des couleurs différentes. Dans la section Décodé, vous verrez les détails du jeton.

Création d’une application API Resource Server :

Ensuite, nous devons créer un projet d’API Web ASP.NET Core nommé APIResourceServer. Il s’agira de notre serveur de ressources, exposant les points de terminaison de l’API à être consommés par les clients avec l’authentification JWT.

Une fois que vous avez créé le Resource Server Project, veuillez installer le package : Microsoft.AspNetCore.Authentication.JwtBearer . Vous pouvez installer le package à l’aide du Gestionnaire de package NuGet pour la solution ou en exécutant la commande suivante dans la console du Gestionnaire de package :

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

Configurez l’authentification JWT pour valider le jeton dans le serveur de ressources :

Nous devons nous assurer que le serveur de ressources valide les jetons JWT provenant du client. Nous devons configurer l’authentification par jeton JWT Bearer dans le fichier de classe Program.cs. Par conséquent, modifiez la classe Program comme suit :

à l’aide de Microsoft.AspNetCore.Authentication.JwtBearer ; à l’aide de Microsoft.IdentityModel.Tokens ; à l’aide de System.Text ; espace de noms APIResourceServer { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args) ; // Ajoute des services au conteneur. builder. Services.AddControllers() . AddJsonOptions(options => { // Cette option utilisera les noms de propriété tels que définis dans les options du modèle C#. JsonSerializerOptions.PropertyNamingPolicy = null ; }); Pour en savoir plus sur la configuration de Swagger/OpenAPI, consultez https://aka.ms/aspnetcore/swashbuckle constructeur. Services.AddEndpointsApiExplorer() ; constructeur. Services.AddSwaggerGen() ; Configurez le générateur d’authentification JWT. Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) . AddJwtBearer(options => { options. TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder. Configuration["Jwt :Issuer"], ValidAudience = constructeur. Configuration["Jwt :Audience"], IssuerSigningKey = nouveau SymmetricSecurityKey(Encoding.UTF8.GetBytes(constructeur. configuration["jwt :clé"])) } ; }); var app = constructeur. Build() ; Configurez le pipeline de requêtes HTTP. si (app. Environment.IsDevelopment()) { app. UseSwagger() ; appli. UseSwaggerUI() ; } app. UseHttpsRedirection() ; Enregistre le middleware d’authentification qui utilise le schéma d’authentification par défaut défini par AddAuthentication. appli. UseAuthentication() ; Enregistre le middleware d'autorisation pour appliquer des stratégies d'autorisation sur les itinéraires de l'application. appli. UseAuthorization() ; Cartographie les itinéraires des contrôleurs. appli. MapControllers() ; appli. exécuter() ; } } }
Présentation du service JWT et des composants middleware :

AddAuthentication : AddAuthentication est utilisé pour configurer les services d’authentification dans une application ASP.NET Core. Lors de sa configuration avec JwtBearerDefaults.AuthenticationScheme , il configure le JWT Bearer comme schéma d’authentification par défaut. Ceci est essentiel pour permettre à l’application d’accepter et de valider les jetons JWT pour l’authentification.

UseAuthentication : UseAuthentication est un composant middleware qui est ajouté au pipeline de requêtes HTTP et qui est responsable de l’appel des schémas d’authentification configurés dans AddAuthentication. Pour JWT, il tente de valider le jeton JWT présent dans l’en-tête d’autorisation de la demande, vérifie si le jeton est valide et définit l’identité de l’utilisateur en fonction des revendications du jeton.

UseAuthorization : UseAuthorization est un autre composant middleware qui vérifie l’identité de l’utilisateur établie par UseAuthentication et applique des politiques d’autorisation sur les routes, les contrôleurs ou les actions. Ceci est important pour sécuriser les points de terminaison afin de s’assurer que seuls les utilisateurs authentifiés et autorisés peuvent y accéder.

Modification appsettings.json fichier :

assurez-vous que les paramètres de l’émetteur, de l’audience et de la clé sont configurés dans votre fichier appsettings.json de la même manière que dans l’application du serveur d’authentification. Veuillez donc modifier le fichier appsettings.json comme suit :

{ « Logging » : { « LogLevel » : { « Default » : « Information », « Microsoft.AspNetCore » : « Warning » } }, « AllowedHosts » : « * », « Jwt » : { « Key » : « KHPK6Ucf/zjvU4qW8/vkuuGLHeIo0l9ACJiTaAPLKbk= », //Clé secrète « Issuer » : « https://localhost:7035 », //URL du domaine du serveur d’authentification « Audience » : « http://localhost:5001 » //URL du domaine d’application client } }
Création du contrôleur d’API :

Ensuite, nous devons créer le contrôleur d’API qui expose les points de terminaison à consommer par les clients. Alors, créez un Videz le contrôleur d’API nommé UsersController dans le dossier Controllers, puis copiez et collez le code suivant :

à l’aide de Microsoft.AspNetCore.Authorization ; à l’aide de Microsoft.AspNetCore.Mvc ; namespace APIResourceServer.Controllers { [Route(« api/[controller] »)] [ApiController] public class UsersController : ControllerBase { // Liste statique pour simuler la base de données des utilisateurs. private static List<User> _users = new List<User> { new User { id = 1, Username = « admin », Email = « [email protected] » }, new User { Id = 2, Username = « user », Email = « [email protected] » }, new User { id = 3, Nom d’utilisateur = « test », email="[email protected] » } } ; GET pour récupérer tous les utilisateurs. [HttpGet] //Pour sécuriser les points de terminaison avec l’authentification JWT, nous devons appliquer l’attribut [Authorize] [Authorize] public ActionResult<List<User>> GetAllUsers() { // Renvoie la liste statique des utilisateurs. retour _users ; } // Méthode GET avec un paramètre pour récupérer un utilisateur spécifique par son ID. [HttpGet(« {id} »)] [Autoriser] public ActionResult<User> GetUser(int id) { // Recherche dans la liste un utilisateur avec l’ID spécifié. var user = _users. FirstOrDefault(u => u.Id == id) ; Si aucun utilisateur n’est trouvé, renvoyez une réponse 404 Not Found. if (user == null) renvoie NotFound() ; S’il est trouvé, renvoyez l’utilisateur. utilisateur récurrent ; } // Méthode POST pour créer un nouvel utilisateur. [HttpPost] [Authorize] public ActionResult<User> CreateUser([FromBody] User user) { // Ajoute le nouvel utilisateur à la liste. _users. Ajouter(utilisateur) ; Renvoie une réponse avec l’emplacement de l’utilisateur nouvellement créé. return CreatedAtAction(nameof(GetUser), new { id = utilisateur. id }, utilisateur) ; } // Méthode PUT pour mettre à jour un utilisateur existant. [HttpPut(« {id} »)] [Authorize] public ActionResult<User> UpdateUser(int id, [FromBody] User user) { // Trouve l’index de l’utilisateur dans la liste. var index = _users. FindIndex(u => u.Id == id) ; Si aucun utilisateur n’est trouvé à cet index, renvoie un 404 Not Found. if (index == -1) return NotFound() ; Mettez à jour l’utilisateur au niveau de l’index spécifique. _users[index] = utilisateur ; Renvoie une réponse 204 Aucun contenu, indiquant que la mise à jour a réussi. return NoContent() ; } // DELETE méthode pour supprimer un utilisateur par ID. [HttpDelete(« {id} »)] [Autoriser] public IActionResult DeleteUser(int id) { // Recherche l’index de l’utilisateur à supprimer. var index = _users. FindIndex(u => u.Id == id) ; Si aucun utilisateur n’est trouvé à cet index, renvoie un 404 Not Found. if (index == -1) return NotFound() ; Supprimez l’utilisateur de la liste. _Utilisateurs. SupprimerAt(index) ; Renvoie une réponse 204 No Content, indiquant que la suppression a réussi. return NoContent() ; } } // Définition du modèle d’utilisateur utilisé dans le contrôleur. public class User { public int Id { get ; set ; } public string Username { get ; set ; } public string Email { get ; set ; } } }
Accès aux services du serveur de ressources avec l’authentification JWT :

Voyons maintenant comment accéder aux services du serveur de ressources avec l’authentification JWT. Nous avons déjà vu comment appeler le point de terminaison de l’API de connexion du serveur d’authentification pour obtenir le jeton JWT. Maintenant, je suppose que vous avez le jeton JWT. Alors, ouvrez ensuite Postman et émettez une requête aux points de terminaison de l’API, qui renverra toutes les données de l’utilisateur, comme indiqué dans l’image ci-dessous :

Création d’une application cliente pour la consommation de ressources avec l’authentification JWT :

Maintenant, nous allons créer une application de console Dot Net consommant les points de terminaison de l’API du serveur de ressources avec l’authentification JWT. Cela signifie qu’il appellera d’abord le point de terminaison de connexion du serveur d’authentification pour obtenir le jeton JWT, puis qu’à l’aide de ce jeton JWT, il consommera tout le serveur de ressources services. Par conséquent, créez une application console Dot Net nommée JWTClientApp, puis modifiez la classe Program comme suit :

à l’aide de System.Net ; en utilisant System.Net.Http.Headers ; à l’aide de System.Text ; en utilisant System.Text.Json ; namespace JWTClientApp { public class Program { // Instance HttpClient utilisée pour effectuer des requêtes HTTP. private static readonly HttpClient httpClient = new HttpClient() ; // URL de base pour les points de terminaison de l’API sur le serveur de ressources. private static readonly string baseUrl = « https://localhost:7239/api/users » ; // Le point d’entrée du programme. static async Task Main(string[] args) { try { // Authentifier et obtenir un jeton JWT du serveur d’authentification. var token = await AuthenticateAndGetToken() ; Console.WriteLine(« Jeton reçu : " + jeton) ; Utilisez le jeton pour effectuer des opérations CRUD. Console.WriteLine(await GetUser(token, 1)) ; Récupérez l’utilisateur avec l’ID 1. Console.WriteLine(await CreateUser(token, new Utilisateur { id = 4, Nom d’utilisateur = « newuser », email = « [email protected] » })) ; Console.WriteLine(await UpdateUser(token, 4, new User { id = 4, Username = « updatedUser », Email = « [email protected] » })) ; Console.WriteLine(await DeleteUser(jeton, 4)) ; Supprimez l’utilisateur avec l’ID 4. Console.ReadKey() ; } catch (Exception ex) { Console.WriteLine(« Erreur : " + ex. Message) ; } } // Méthode d’authentification par l’envoi d’identifiants et la réception d’un jeton JWT. static async Task<string> AuthenticateAndGetToken() { // URL du point de connexion final. var loginUrl = « https://localhost:7035/api/Users/Login » ; // Corps de la requête contenant les identifiants de connexion. var loginRequestBody = new { Username = « admin », Password = « password » } ; var requestContent = new StringContent(JsonSerializer.Serialize(loginRequestBody), Encoding.UTF8, « application/json ») ; // Effectuer une requête POST à l’URL de connexion. var réponse = await httpClient.PostAsync(loginUrl, requestContent) ; if ( !réponse. IsSuccessStatusCode) { // Si la connexion échoue, lisez et renvoyez le message d’erreur. var errorContent = attendre la réponse. Content.ReadAsStringAsync() ; return $"Échec de la connexion : {errorContent} » ; } // Lire le contenu de la réponse et extraire le jeton. var loginResponseContent = attendre la réponse. Content.ReadAsStringAsync() ; var tokenObject = JsonSerializer.Deserialize<JsonElement>(loginResponseContent) ; return tokenObject.GetProperty(« Token »). GetString() ; } // Méthode pour obtenir les données d'un utilisateur. static async Task<string> GetUser(string token, int userId) { // Définit l’en-tête Authorization avec le jeton JWT reçu. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(« Bearer », token) ; var response = await httpClient.GetAsync(baseUrl + $"/{userId} ») ; return await ProcessResponse(response, « Get User ») ; } // Méthode pour créer un nouvel utilisateur. static async Task<string> CreateUser(string token, User user) { // Définit l’en-tête Authorization et effectue une requête POST pour créer un nouvel utilisateur. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(« Bearer », token) ; var response = await httpClient.PostAsync(baseUrl, new StringContent(JsonSerializer.Serialize(user), Encoding.UTF8, « application/json »)) ; return await ProcessResponse(response, « Create User ») ; } // Méthode pour mettre à jour un utilisateur. static async Task<string> UpdateUser(string token, int userId, User user) { // Définit l’en-tête Authorization et effectue une requête PUT pour mettre à jour l’utilisateur. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(« Bearer », token) ; var response = await httpClient.PutAsync(baseUrl + $"/{userId} », new StringContent(JsonSerializer.Serialize(user), Encoding.UTF8, « application/json »)) ; return await ProcessResponse(réponse, « Mettre à jour l’utilisateur ») ; } // Méthode pour supprimer un utilisateur. static async Task<string> DeleteUser(string token, int userId) { // Définit l’en-tête Authorization et effectue une requête DELETE pour supprimer l’utilisateur. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(« Bearer », token) ; var response = await httpClient.DeleteAsync(baseUrl + $"/{userId} ») ; return await ProcessResponse(response, « Delete User ») ; } // Méthode d’assistance pour traiter et formater la réponse des requêtes HTTP. private static async Task<string> ProcessResponse(HttpResponseMessage response, string action) { var responseBody = await response. Content.ReadAsStringAsync() ; si (réponse. IsSuccessStatusCode) { return $"{action} succeeded : {responseBody} » ; } // Gérer différents codes d’état HTTP et personnaliser le message d’erreur. commutateur (réponse. StatusCode) { case HttpStatusCode.Unauthorized : return $"{action} Échec : Non autorisé - Le jeton peut être invalide ou expiré » ; case HttpStatusCode.Forbidden : return $"{action} Echec : Interdit - Permissions insuffisantes » ; default : return $"{action} Échec : {réponse. StatusCode} - {responseBody}" ; } } } // Définition du modèle Utilisateur. public class User { public int Id { get ; set ; } public string Username { get ; set ; } public string Email { get ; set ; } } }
Sortie :

Avantages et inconvénients de l’utilisation de l’authentification basée sur les jetons dans ASP.NET API Web principale

L’authentification basée sur les jetons dans ASP.NET API Web Core offre plusieurs avantages, mais présente également certains inconvénients. Ils sont les suivants :

Avantages de l’utilisation de l’authentification basée sur les jetons dans ASP.NET API Web de base
  • Étant sans état signifie que les équilibreurs de charge peuvent envoyer une requête client à n’importe quel serveur, car il n’y a pas de dépendance spécifique à la session sur un seul serveur.
  • Les jetons peuvent être conçus pour être autonomes, transportant toutes les informations utilisateur nécessaires au traitement d’une demande, ce qui réduit le risque d’attaques CSRF (Cross-Site Request Forgery). Les jetons peuvent également être chiffrés pour plus de sécurité.
  • L’authentification basée sur les jetons peut facilement prendre en charge l’authentification multiplateforme sur différents types de clients (applications web, mobiles et de bureau) car elle utilise des en-têtes HTTP standard pour transporter les jetons.
Inconvénients de l’utilisation de l’authentification basée sur les jetons dans ASP.NET API Web principale
  • Les jetons doivent être stockés en toute sécurité côté client. Une mauvaise manipulation peut entraîner des vulnérabilités, en particulier dans le cas des attaques XSS (Cross-Site Scripting), où un attaquant peut voler le jeton et obtenir un accès non autorisé.
  • La gestion de l’expiration du jeton est importante. Si l’expiration est trop courte, les utilisateurs peuvent être tenus de s’authentifier fréquemment. S’il est trop long, il peut augmenter le risque d’utilisation abusive du jeton s’il est compromis.
  • Si la charge utile de données comprend trop de revendications, sa taille peut augmenter. L’encodage, le décodage et la validation des jetons sur chaque requête peuvent également ajouter une surcharge de calcul.

Dans le prochain article, je vais voir comment implémenter Refresh Token dans ASP.NET application API Web principale. Ici, dans cet article, j’explique l’authentification basée sur des jetons à l’aide de JWT dans ASP.NET application API Web centrale à l’aide d’un exemple. J’espère que vous apprécierez cet article sur l’authentification JWT dans ASP.NET API Web de base.

Tutoriels Dot Net

À propos de l’auteur : Pranaya Rout

Pranaya Rout a publié plus de 3 000 articles au cours de ses 11 ans de carrière. Pranaya Rout a une très bonne expérience des technologies Microsoft, y compris C#, VB, ASP.NET MVC, ASP.NET Web API, EF, EF Core, ADO.NET, LINQ, SQL Server, MYSQL, Oracle, ASP.NET Core, Cloud Computing, Microservices, Design Patterns et continue d’apprendre de nouvelles technologies.