logo
    • Accueil
    • Catégories
    • A propos
  • fr-languageFrançais
NodejsPar Pierre Colart

NestJs - Authentification

Introduction

L'authentification est un aspect crucial de nombreuses applications Web modernes. L'authentification consiste à vérifier l'identité d'un utilisateur avant de leur permettre d'accéder aux ressources protégées de l'application. Dans Nest.js, l'authentification peut être mise en œuvre à l'aide d'une variété de stratégies d'authentification, telles que JWT (JSON Web Token), OAuth, OAuth2 et bien d'autres.

Dans Nest.js, vous pouvez implémenter l'authentification en utilisant les middleware d'authentification fournis par le framework ou en écrivant vos propres middleware d'authentification personnalisés. Les middleware d'authentification sont des fonctions qui s'exécutent avant que la requête ne soit traitée par votre application et vérifient l'identité de l'utilisateur en fonction des stratégies d'authentification configurées.

Passport

Passport.js est une bibliothèque d'authentification très populaire pour Node.js. Elle permet d'ajouter facilement des stratégies d'authentification à une application, telles que l'authentification par mot de passe, l'authentification via les réseaux sociaux ou encore l'authentification via des services tiers. NestJS est un framework Node.js pour la construction d'applications back-end hautement évolutives et performantes.

L'intégration de Passport.js avec NestJS est relativement simple et offre de nombreuses possibilités pour gérer l'authentification de manière efficace et sécurisée. En utilisant Passport.js avec NestJS, il est possible de mettre en place des stratégies d'authentification basées sur des jetons, des cookies, des sessions, ou même des protocoles tels que OAuth2.

L'une des principales caractéristiques de Passport.js est sa modularité. En effet, il est possible d'ajouter des stratégies d'authentification personnalisées en fonction des besoins de l'application. De plus, Passport.js offre une grande flexibilité en ce qui concerne la gestion des erreurs, la personnalisation des messages d'erreur, ainsi que la gestion des sessions utilisateur.

Grâce à l'intégration de Passport.js avec NestJS, il est donc possible de mettre en place une authentification sécurisée et personnalisée pour son application back-end. Que ce soit pour des applications web, des API, ou des applications mobiles, l'utilisation de Passport.js avec NestJS est une solution de choix pour gérer l'authentification utilisateur.

Passport.js permet de mettre en place différentes stratégies d'authentification pour permettre à un utilisateur de s'identifier sur une application. Parmi les stratégies les plus couramment utilisées, on trouve notamment la "local strategy", qui permet d'authentifier un utilisateur à partir de son email et de son mot de passe. Cette stratégie est utilisée dans la plupart des cas, pour permettre aux utilisateurs de s'identifier avec leur propre compte sur l'application.

Une autre stratégie couramment utilisée est la "jwt strategy", qui permet d'authentifier un utilisateur à partir d'un jeton. Cette stratégie est souvent utilisée pour les applications qui utilisent un protocole d'authentification basé sur des jetons, comme OAuth2. La "jwt strategy" utilise la bibliothèque jsonwebtoken pour vérifier la validité du jeton fourni par l'utilisateur.

En plus des stratégies d'authentification "local" et "jwt", Passport.js permet également de mettre en place des stratégies d'authentification basées sur des réseaux sociaux ou des services tiers. Par exemple, la stratégie "GoogleOAuth" permet d'authentifier un utilisateur à partir de son compte Google, tandis que les stratégies "Facebook" et "Twitter" permettent d'authentifier un utilisateur à partir de son compte Facebook ou Twitter.

Mise en oeuvre

Pour configurer le passeport, trois éléments doivent être pris en compte :

  • La stratégie d'authentification : elle est utilisée par Passport pour vérifier l'identité de l'utilisateur lorsqu'il se connecte à l'application. Passport propose différentes stratégies d'authentification, telles que "local", "JWT", "OAuth", etc. Dans ce cas, nous allons utiliser la stratégie "passport-jwt".

  • Le middleware applicatif : il permet de définir comment Passport va être utilisé dans l'application. Par exemple, il est possible de configurer les routes qui nécessitent une authentification, ou encore de définir des messages d'erreur personnalisés.

  • La séance (facultative) : elle permet de stocker les informations d'authentification de l'utilisateur dans une session. Si la séance n'est pas utilisée, les informations d'authentification devront être fournies à chaque requête.

Une fois que ces éléments sont configurés, Passport peut être utilisé pour sécuriser les routes de l'application. Lorsqu'un utilisateur tente d'accéder à une route protégée, Passport vérifie son identité en utilisant la stratégie d'authentification configurée.

Pour installer la stratégie "passport-jwt", vous pouvez utiliser les commandes npm suivantes :

 npm i passport-jwt @types/passport-jwt
npm i jsonwebtoken @types/jsonwebtoken

Module d'authentification

Ce module permet de configurer la stratégie d'authentification JWT (JSON Web Token) en utilisant le package "passport-jwt". Pour cela, il étend la classe "Strategy" fournie par ce package. Voici un exemple de cette classe :

 @Injectable()
export default class JwtStrategy extends Strategy {
   constructor(private readonly authenticationService: AuthenticationService) {
       super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            passReqToCallback: true,
            secretOrKey: 'secret'
        }, async (req, payload, next) => {
            return await this.verify(req, payload, next);
        });
        passport.use(this);
    }

   public async verify(req, payload, done) {
       const isValid = await this.authenticationService.validateUser(payload);
        if (!isValid) {
           return done('Unauthorized', null);
        } else {
           return done(null, payload);
        }
   }
}

Le constructeur de cette classe permet de passer différents paramètres de configuration :

  • L'option "jwtFromRequest" accepte une fonction permettant d'extraire le jeton JWT de la requête. Dans cet exemple, la fonction "ExtractJwt.fromAuthHeaderAsBearerToken()" est utilisée pour sélectionner le jeton dans l'en-tête de la demande à l'aide de l'en-tête "Authorization", et sélectionner le jeton qui suit le mot "Bearer".

  • Le paramètre "passReqToCallback" prend un booléen pour indiquer si vous souhaitez obtenir la requête (req) dans la méthode de vérification (verify) qui sera appelée plus tard.

  • Le paramètre "secretOrKey" prend une chaîne ou un tampon pour vérifier la signature du jeton.

D'autres paramètres sont disponibles pour configurer la stratégie, mais pour cette authentification, ils ne sont pas nécessaires.

Ensuite, nous passons une fonction de rappel "verify" qui a pour but de vérifier si le jeton est valide et si la charge utile obtenue à partir du jeton est valide ou non. Cette fonction est asynchrone et exécute la méthode "verify" qui appelle l'authenticationService afin de valider l'utilisateur avec la charge utile en paramètre.

Si l'utilisateur est valide, nous renvoyons la charge utile, sinon nous renvoyons une erreur pour indiquer que la charge utile n'est pas valide.

Service d'authentification

Comme mentionné précédemment, pour vérifier la charge utile obtenue à partir du jeton, il est nécessaire d'appeler la méthode "validateUser" fournie par le service "AuthenticationService". Ce service implémentera également une méthode pour générer le jeton pour l'utilisateur connecté.

Voici un exemple d'implémentation de ce service :

 @Injectable()
export class AuthenticationService {
   constructor(private readonly userService: UserService) { }

   createToken(email: string, ttl?: number) {
        const expiresIn = ttl || 60 * 60;
        const secretOrKey = 'secret';
        const user = { email };
        const token = jwt.sign(user, secretOrKey, { expiresIn });
        return {
            expires_in: expiresIn,
            access_token: token,
        };
   }

   async validateUser(payload: { email: string; password: string }): Promise<boolean> {
        const user = await this.userService.findOne({
            where: { email: payload.email }
        });
        return !!user;
   }
}

Ce service injecte le service "UserService" afin de trouver l'utilisateur correspondant à la charge utile passée à la méthode "validateUser". Si l'e-mail présent dans la charge utile permet de trouver l'utilisateur et si cet utilisateur dispose d'un jeton valide, il peut poursuivre le processus d'authentification.

Pour fournir un jeton à l'utilisateur qui tente de se connecter, le service implémente la méthode "createToken", qui prend comme paramètres un e-mail et un TTL facultatif. Le TTL (Time-To-Live) permet de définir la durée de vie du jeton, en secondes. Dans l'exemple donné, le TTL par défaut est d'une heure (60 * 60 secondes).

La méthode "createToken" utilise le package "jsonwebtoken" pour signer le jeton en utilisant une clé secrète. Le jeton contient l'e-mail de l'utilisateur et une durée de validité définie par le TTL. La méthode renvoie un objet contenant la durée de validité du jeton et le jeton lui-même.

Conclusion

En conclusion, nous avons vu comment configurer la stratégie d'authentification JWT avec le package "passport-jwt" et comment implémenter le service "AuthenticationService" pour vérifier la charge utile du jeton et générer un jeton valide pour l'utilisateur connecté. Nous avons également vu comment utiliser la méthode "createToken" de ce service pour générer un jeton, qui sera ensuite utilisé pour sécuriser les routes de l'application.

La configuration de la stratégie JWT et la validation du jeton sont des étapes cruciales pour sécuriser une application web. En utilisant Passport et les packages associés, nous pouvons facilement mettre en place un système d'authentification sécurisé basé sur des jetons JWT.

Il est important de noter que la sécurité de l'application ne se limite pas à l'authentification. D'autres mesures de sécurité, telles que la protection contre les injections SQL et la vérification des autorisations, doivent également être mises en place pour garantir que l'application est sécurisée et protégée contre les attaques malveillantes.

Pierre Colart

Developpeur et architecte passionné, qui souhaite partagé son univers et ses découvertes afin de rendre les choses plus simple pour chacun

Voir le profil

Les derniers articles

Sequences, Time Series et Prediction

© 2023 Switch case. Made with by Pierre Colart