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.
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é.
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.
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.
app.use('/api/users', require('./routes/user'));
Retrouvez les premiers articles du projet ici ⬇️
– Simple Blog From Scratch Part1
– Simple Blog From Scratch Part2
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.