LILINE’S LAB

Projet : Simple Blog From Scratch Part3

par | Fév 22, 2024 | Développement, Express, NodeJS, Projets, Simple Blog From Scratch

Dans cet article nous allons voir comment le compte de le compte du premier utilisateur créé automatiquement dans l’article précédent va pouvoir se connecter au blog en utilisant une double-authentification.

Controller

Le controller user contient les fonctions login et verifyotp.
La fonction login va vérifier si le compte existe et, s’il existe et que le mail et le mot de passe renseignés sont corrects, va envoyer un code OTP sur l’adresse email renseignée. Cette fonction utilise le middleware sendmail qui permet d’envoyer un mail grâce à l’utilisation de nodemailer.
La fonction verityotp va vérifier si le code OTP entré correspond bien à celui généré par la fonction login.
Le compte du propriétaire du blog est créé lors de la mise en place du blog et c’est le seul compte qui pourra poster des articles sur le blog.

JavaScript
const db = require("../models"); 
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
require('dotenv').config();
const auth = require("../middleware/auth");
const { sendEmail } = require('../middleware/sendmail');
const messages = require('../messages');

exports.login = async (req, res, next) => {
  try {
    // On regarde si l'utilisateur existe
    const user = await db.User.findOne({
      where: {email: req.body.email},
    });
  // Si l'utilisateur n'existe pas
  if (user === null) {
    return res.status(401).json({ error: messages.USER_CONNEXIONIMPOSSIBLE });
    } // Si l'utilisateur existe 
      else {
      // On vérifie si le mot de passe entré est bon
      const hashed = await bcrypt.compare(req.body.password, user.password);
      // Si le mot de passe n'est pas bon
      if (!hashed) {
        return res.status(401).json({ error: messages.USER_MDPINCORRECT });
      } // Si le mot de passe est bon
        else {
        const { email } = req.body;
        // On créé un code OTP que l'on inscrit en BDD dans les données de l'utilisateur, code qui expire au bout de 5min
        this.otpCode = Math.floor(100000 + Math.random() * 900000);
        const expires = new Date(Date.now() + 5*60*1000);
        user.otp = this.otpCode;
        user.otpcreated = Date.now();
        user.otpexpires = expires;
        await user.save({ fields: ["otp", "otpcreated", "otpexpires"],});
        // ce code OTP est ensuite envoyé sur le mail de l'utilisateur indiqué lors de l'inscription 
        try {
          await sendEmail(email, messages.OTP_TITLE, messages.OTP_MSG + this.otpCode);
          return res.status(200).send({ message: messages.OTP_SENDMAILMSG + email });
          } catch (error) {
            return res.status(500).send({ message: messages.OTP_NOTSENT });
          }
      } 
    } 
  } catch (error) {
    return res.status(500).json({ error: messages.SERVEUR_ERROR });
  }
};

exports.verifyotp = async (req, res, next) => {
  const user = await db.User.findOne({ where: {email: req.body.email}, });
  const thisotp = await db.User.findOne({
    attributes: ["otp", "otpcreated", "otpexpires"], 
    where: {email: req.body.email}, 
    raw: true,
  });
  const thisotpverify = thisotp.otp;
  const thisotpexpires = thisotp.otpexpires;
  const dateotp = new Date(thisotpexpires)
  const datenowtocompare = dateotp.getTime();
  const datenow = Date.now();  
  const { otp } = req.body;
  // On compare le code OTP rentré par l'utilisateur et celui présent en BDD
  if (otp === thisotpverify && otp!=0 && datenowtocompare > datenow) {
    res.status(200).json({
      message: messages.USER_CONNECTED,
      username: user.username,
      email: user.email,
      userId: user.id,
      token: jwt.sign({userId: user.id}, process.env.TOKEN, {expiresIn: '24h'}),
  })
  } else {
    res.status(401).send({ message: messages.OTP_INVALID });
  }
  
exports.getUser = async (req, res, next) => {
  try {
    const userId = auth.getUserID(req);
    await db.User.findOne({ attributes: ["id", "username", "email"], where: { id: userId } });
    res.status(200).json({message : messages.USER_CONNECTED});
  } catch (error) {
    return res.status(500).json({ error: messages.SERVEUR_ERROR });
  }
  
};

Sendmail

Afin d’envoyer le code OTP sur l’adresse mail de l’utilisateur un middleware utilisant Nodemailer est utilisé.

JavaScript
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: process.env.MAIL_HOST,
  port: process.env.MAIL_PORT,
  auth: {
      user: process.env.MAIL_ACCOUNT,
      pass: process.env.MAIL_PSWD
  }
})

exports.sendEmail = (to, subject, html) => {

    const email_message = {
        from: process.env.MAIL_ACCOUNT,
        to: to,
        subject: subject,
        text: html
    };
    
    transporter.sendMail(email_message)    
}

Routes

Les routes concernant l’utilisateur sont créées.

JavaScript
const express = require('express'); 
const router = express.Router();
const ctrl = require("../controllers/user");

router.post("/login", ctrl.login);
router.post("/verify", ctrl.verifyotp );
router.get("/loggedIn", ctrl.getUser);

module.exports = router;

app.js

Dans app.js la ligne ci-dessous est rajoutée afin de pouvoir utiliser les routes concernant l’utilisateur.

JavaScript
app.use('/api/users', require('./routes/user'));

Retrouvez les premiers articles du projet ici ⬇️

Simple Blog From Scratch Part1
Simple Blog From Scratch Part2


logo du site

   


Consultante spécialisée dans les technologies Microsoft, je justifie de plus de 14 ans d’expérience dans le secteur IT.
Mon parcours professionnel, riche et varié, m’a permis de développer de solides compétences, tant techniques qu’humaines. Je suis reconnue pour ma capacité à analyser rapidement les enjeux techniques et à concevoir des solutions pertinentes, y compris sur des problématiques complexes.
Mon approche proactive, alliée à mes compétences en développement, me permet de proposer des évolutions efficaces, toujours en cohérence avec les objectifs métiers.
En parallèle de mon activité professionnelle, je prends plaisir à approfondir mes compétences techniques en réalisant des projets personnels. Je développe notamment des jeux web basés sur React et PHP, ainsi que des applications orientées métier avec SPFx.