Guide Complet pour la Création d'un Système d'Authentification avec Express, Passport et MongoDB en utilisant les API Google et Github

Guide Complet pour la Création d'un Système d'Authentification avec Express, Passport et MongoDB en utilisant les API Google et Github

  1. Installation des Packages :

    • Tout d'abord, assurez-vous d'avoir initialisé votre projet Node.js et d'avoir un fichier package.json. Si vous n'avez pas encore de fichier package.json, vous pouvez le créer en exécutant npm init -y dans votre terminal.
  • dotenv : Ce package permet de charger les variables d'environnement à partir d'un fichier .env dans process.env. Pour l'installer, exécutez la commande suivante dans votre terminal : npm install dotenv

  • express : Express est un framework Node.js utilisé pour créer des applications web. Pour l'installer, exécutez : npm install express

  • body-parser : Utilisé pour analyser les données du corps des requêtes HTTP. Installez-le avec : npm install body-parser

  • mongoose : Mongoose est une librairie d'ODM (Object Data Modelling) pour MongoDB. Installez-le avec : npm install mongoose

  • express-session : Ce package permet de gérer les sessions dans Express. Installez-le via : npm install express-session

  • passport-local-mongoose : Ce module simplifie l'utilisation de Passport avec Mongoose pour l'authentification locale. Installez-le avec : npm install passport-local-mongoose

  • passport-google-oauth20 : Utilisé pour l'authentification Google OAuth. Installez-le avec : npm install passport-google-oauth20

  • passport-github2 : Pour l'authentification avec Github. Installez-le avec : npm install passport-github2

  • mongoose-findorcreate : Module pour la création ou recherche d'objets dans MongoDB. Installez-le avec : npm install mongoose-findorcreate

  • EJS, qui signifie Embedded JavaScript, est un moteur de modèles JavaScript simple et efficace qui vous permet d'incorporer du code JavaScript directement dans vos fichiers HTML. Il aide à générer du contenu dynamique côté serveur en utilisant des modèles: npm install ejs

  1. Configuration du serveur et des routes :

    • Mettez en place le serveur Express, configurez les vues avec EJS et le body-parser:

      ```javascript const express = require("express"); const bodyParser = require("body-parser"); const mongoose = require("mongoose");

const app = express();

app.use(express.static("public")); app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({ extended: true }));


    * Initialisez et configurez les sessions, Passport et connectez-vous à la base de données MongoDB:

    * ```javascript
        // Initialisation et configuration des sessions, Passport et connexion à MongoDB

        // Import des modules nécessaires
        const session = require('express-session');
        const passport = require("passport");
        const passportLocalMongoose = require("passport-local-mongoose");

        // Configuration de la session
        app.use(session({
          secret: "Our little secret.",
          resave: false,
          saveUninitialized: false
        }));

        // Initialisation de Passport et de la session
        app.use(passport.initialize());
        app.use(passport.session());

        // Connexion à la base de données MongoDB
        mongoose.connect("mongodb://127.0.0.1:27017/userDB", {useNewUrlParser: true});
        mongoose.set("useCreateIndex", true);

        // Définition du schéma utilisateur avec Passport-Local Mongoose
        const userSchema = new mongoose.Schema ({
          email: String,
          username: String,
          password: String,
          googleId: String,
          githubId: String,
          secret: String
        });

        userSchema.plugin(passportLocalMongoose);

        // Création du modèle utilisateur
        const User = new mongoose.model("User", userSchema);

        // Configuration de Passport pour utiliser la stratégie locale
        passport.use(User.createStrategy());

        passport.serializeUser(function(user, done) {
          done(null, user.id);
        });

        passport.deserializeUser(function(id, done) {
          User.findById(id, function(err, user) {
            done(err, user);
          });
        });

Dans ce code, nous initialisons et configurons la session en définissant un secret, en spécifiant les options de rechargement et de sauvegarde de la session. Ensuite, nous initialisons Passport, lui attachons la session, et configurons la connexion à la base de données MongoDB avec Mongoose.

Nous définissons le schéma utilisateur avec les champs requis et utilisons Passport-Local Mongoose pour simplifier l'authentification locale. Le modèle utilisateur est créé à partir de ce schéma, et Passport est configuré pour utiliser la stratégie locale.

En suivant ces étapes, votre application sera prête à gérer les sessions, l'authentification avec Passport, et à se connecter à la base de données MongoDB.

  •   // Définition du schéma Mongoose pour les utilisateurs avec les champs nécessaires
      const userSchema = new mongoose.Schema ({
        email: String,
        username: String,
        password: String,
        googleId: String,
        githubId: String,
        secret: String
        //profilePic: String
      });
    
      // Utilisation du plugin passportLocalMongoose pour simplifier l'authentification locale
      userSchema.plugin(passportLocalMongoose);
      userSchema.plugin(findOrCreate);
    
      // Création du modèle User à partir du schéma
      const User = new mongoose.model("User", userSchema);
    
  • Dans ce code, nous définissons le schéma Mongoose pour les utilisateurs avec les champs email, username, password, googleId, githubId et secret. En utilisant le plugin passportLocalMongoose, nous simplifions l'authentification locale en reliant Passport au schéma utilisateur.

  1. Configurez les stratégies Passport pour l'authentification Google et Github avec les informations d'identification appropriées:
  •   // Configuration des stratégies Passport pour l'authentification Google et Github
    
      // Configuration de la stratégie Google OAuth 2.0
      passport.use(new GoogleStrategy({
        clientID: process.env.GOOGLE_CLIENT_ID,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        callbackURL: "http://localhost:3000/auth/google/secrets",
        userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
      },
      function(accessToken, refreshToken, profile, cb) {
        User.findOrCreate({ googleId: profile.id }, function (err, user) {
          return cb(err, user);
        });
      }
      ));
    
      // Configuration de la stratégie Github
      passport.use(new GitHubStrategy({
        clientID: process.env.GITHUB_CLIENT_ID,
        clientSecret: process.env.GITHUB_CLIENT_SECRET,
        callbackURL: "http://localhost:3000/auth/github/secrets"
      },
      function(accessToken, refreshToken, profile, cb) {
        User.findOrCreate({ githubId: profile.id }, function (err, user) {
          return cb(err, user);
        });
      }
      ));
    

Dans ce code, nous configurons la stratégie Google OAuth 2.0 en utilisant le module passport-google-oauth20. Nous fournissons les identifiants de client Google (clientID, clientSecret), l'URL de rappel (callbackURL), et la manière de récupérer le profil utilisateur. Lorsqu'un utilisateur se connecte via Google, nous recherchons ou créons un nouvel utilisateur dans la base de données avec l'identifiant Google.

De même, pour la stratégie Github, nous utilisons le module passport-github2 pour configurer l'authentification avec Github. Nous fournissons les identifiants de client Github, l'URL de rappel et la logique pour gérer l'authentification Github.

En intégrant ce code dans votre application, vous serez en mesure de gérer l'authentification des utilisateurs avec leurs comptes Google et Github en utilisant Passport.

  1. Mise en place des Routes :

  2.  app.get("/", function(req, res){
       res.render("home");
     });
    
     // Authentification avec Google
     app.get("/auth/google",
       passport.authenticate("google", { scope: ["profile"] })
     );
    
     // Callback de connexion Google
     app.get("/auth/google/secrets",
       passport.authenticate("google", { failureRedirect: "/login" }),
       function(req, res) {
           // Redirection après l'authentification réussie
           res.redirect("/secrets");
       }
     );
    
     // Authentification avec Github
     app.get("/auth/github",
       passport.authenticate("github", { scope: ["user:email"] })
     );
    
     // Callback de connexion Github
     app.get("/auth/github/secrets",
       passport.authenticate("github", { failureRedirect: "/login" }),
       function(req, res) {
           // Redirection après l'authentification réussie
           res.redirect("/secrets");
       }
     );
    
     // Vérification de l'authentification et redirection
     app.get("/secrets",
       function(req, res){
           if(req.isAuthenticated()){
               res.render("secrets");
           } else {
               res.redirect("/login");
           }
       }
     );
    

Dans ce code, nous avons défini les routes pour les pages d'accueil, d'authentification Google et Github, ainsi que les routes de vérification et de redirection après l'authentification.

  • La route "/" affiche la page d'accueil.

  • Les routes "/auth/google" et "/auth/github" dirigent l'utilisateur vers les pages d'authentification Google et Github respectivement.

  • Les routes "/auth/google/secrets" et "/auth/github/secrets" gèrent le retour de l'authentification Google et Github, et redirigent l'utilisateur vers la page "/secrets" après une authentification réussie.

  • La route "/secrets" vérifie si l'utilisateur est authentifié, et affiche la page de secrets s'il l'est, sinon redirige vers la page de connexion.

En ajoutant ces routes à votre application Express, vous pourrez gérer l'authentification avec Google et Github, ainsi que la vérification et redirection des utilisateurs après l'authentification.

  1. Gestion des Vues :
  • Créez les vues EJS pour les pages d'accueil, de connexion, d'inscription et pour afficher les secrets des utilisateurs:

  • Pour créer les vues EJS correspondantes aux pages d'accueil, de connexion, d'inscription et pour afficher les secrets des utilisateurs, vous pouvez utiliser le modèle d'utilisateur que vous avez fourni. Voici à quoi pourraient ressembler ces vues EJS :

  • 1.Page d'accueil home.ejs :


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Accueil</title>
</head>
<body>
    <h1>Bienvenue sur la page d'accueil</h1>
</body>
</html>
  1. Page de connexion login.ejs :
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Connexion</title>
</head>
<body>
    <h1>Connectez-vous</h1>
    <form action="/login" method="post">
        <input type="text" name="username" placeholder="Nom d'utilisateur">
        <input type="password" name="password" placeholder="Mot de passe">
        <button type="submit">Connexion</button>
    </form>
</body>
</html>
  1. Page d'inscription register.ejs :

    • ```xml

<!DOCTYPE html> Inscription

Inscription

Inscription


        4. Page pour afficher les secrets des utilisateurs secrets.ejs :  


        ```xml

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Secrets</title>
        </head>
        <body>
            <h1>Les Secrets</h1>
            <% if(user) { %>
                <p>Bienvenue, <%= user.username %>!</p>
                <p>Voici les secrets</p>
            <% } else { %>
                <p>Veuillez vous connecter pour voir les secrets</p>
            <% } %>
        </body>
        </html>

En utilisant ces vues EJS, vous pourrez afficher les différentes pages de votre application, y compris la page d'accueil, de connexion, d'inscription et la page pour afficher les secrets des utilisateurs, en fonction du modèle d'utilisateur que vous avez fourni.

  • Voici un exemple complet combinant la configuration de Passport.js pour l'authentification Google et Github, la configuration des routes, ainsi que la configuration d'EJS pour les vues :

  • ```javascript

    require('dotenv').config(); const express = require("express"); const bodyParser = require("body-parser"); const mongoose = require("mongoose"); const session = require('express-session'); const passport = require("passport"); const passportLocalMongoose = require("passport-local-mongoose"); const GoogleStrategy = require('passport-google-oauth20').Strategy; const GithubStrategy = require('passport-github2') const findOrCreate = require('mongoose-findorcreate');

    const app = express();

    app.use(express.static("public")); app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({ extended: true }));

    app.use(session({ secret: "Our little secret.", resave: false, saveUninitialized: false }));

    app.use(passport.initialize()); app.use(passport.session());

    mongoose.connect("mongodb://127.0.0.1:27017/userDB", {useNewUrlParser: true}); mongoose.set("useCreateIndex", true);

    const userSchema = new mongoose.Schema ({ email: String, username: String, password: String,

    googleId: String, githubId: String, secret: String //profilePic: String });

    userSchema.plugin(passportLocalMongoose); userSchema.plugin(findOrCreate);

    const User = new mongoose.model("User", userSchema);

    passport.use(User.createStrategy());

    passport.serializeUser(function(user, done) { done(null, user.id); });

    passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); });

    passport.use(new GoogleStrategy({ clientID: "252883811050-08s9lh3ob91j6g4jq2knhi7eejoqvj..", clientSecret: "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", callbackURL: "localhost:3000/auth/google/secrets", userProfileURL: "googleapis.com/oauth2/v3/userinfo" }, function(accessToken, refreshToken, profile, cb) { console.log(profile);

    User.findOrCreate({ username: profile.displayName, googleId: profile.id }, function (err, user) { return cb(err, user); }); } ));

    passport.use(new GithubStrategy({ clientID: "c54b6f49cc6552b177d9", clientSecret: "5b921c767d1a00a7250d189bc3987fe4c187881d", callbackURL: "127.0.0.1:3000/auth/github/secrets"}, //userProfileURL: "githubapis.com/oauth2/v3/userinfo" }, function(accessToken, refreshToken, profile, cb) { console.log(profile);

    User.findOrCreate({ username: profile.displayName, githubId: profile.id }, function (err, user) { return cb(err, user); }); } ));

    app.get("/", function(req, res){ res.render("home"); });

    app.get("/auth/google", passport.authenticate('google', { scope: ["profile"] }) );

    app.get("/auth/github", passport.authenticate('github', { scope: ["profile"] }) );

app.get("/auth/google/secrets", passport.authenticate('google', { failureRedirect: "/login" }), function(req, res) { // Successful authentication, redirect to secrets. res.redirect("/secrets"); });

app.get("/auth/github/secrets", passport.authenticate('github', { failureRedirect: "/login" }), function(req, res) { // Successful authentication, redirect to secrets. res.redirect("/secrets"); });

app.get("/login", function(req, res){ res.render("login"); });

app.get("/register", function(req, res){ res.render("register"); });

app.get("/secrets", function(req, res){ User.find({"secret": {$ne: null}}, function(err, foundUsers){ if (err){ console.log(err); } else { if (foundUsers) { res.render("secrets", {usersWithSecrets: foundUsers}); } } }); });

app.get("/submit", function(req, res){ if (req.isAuthenticated()){ res.render("submit"); } else { res.redirect("/login"); } });

app.post("/submit", function(req, res){ const submittedSecret = req.body.secret;

//Once the user is authenticated and their session gets saved, their user details are saved to req.user. // console.log(req.user.id);

User.findById(req.user.id, function(err, foundUser){ if (err) { console.log(err); } else { if (foundUser) { foundUser.secret = submittedSecret; foundUser.save(function(){ res.redirect("/secrets"); }); } } }); });

app.get("/logout", function(req, res){ req.logout(); res.redirect("/"); });

app.post("/register", function(req, res){

const { username, password } = req.body;

if (password.length < 6) { console.log("Le mot de passe doit contenir au moins 6 caractères."); res.redirect("/register"); return; }

User.register({ username: username }, password, function(err, user){ if (err) { console.log(err); res.redirect("/register"); } else { passport.authenticate("local")(req, res, function(){ res.redirect("/secrets"); }); } });

});

app.post("/login", function(req, res){

const user = new User({ username: req.body.username, password: req.body.password });

req.login(user, function(err){ if (err) { console.log(err); } else { passport.authenticate("local")(req, res, function(){ res.redirect("/secrets"); }); } });

});

//clientID:"252883811050-08s9lh3ob91j6g4jq2knhi7eejoqvj..", //clientSecret:"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",

app.listen(3000, function() { console.log("Server started on port 3000."); });

```

  • Assurez-vous d'ajuster le code en fonction de votre configuration et de l'environnement dans lequel vous exécutez votre application. Ce code combine la configuration de Passport.js, la mise en place des routes, et l'utilisation de EJS pour gérer les vues de l'application.