(Question posted using a translator).
My problem is quite simple: I generate a random token upon the user’s login, but it’s impossible for me to retrieve it (I should specify that the token expires after about an hour and that with each login, a unique and random token is generated to increase the security of the application).
Therefore, the login works quite well; I retrieve the user ID obtained at registration with the username. Once registered, it is possible to log in with the email and password.
I will present my code to you.
The jwt file that allows me to generate my token:
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = {
//
generateTokenForUser: function (userData) {
// génération du token
return jwt.sign(
{
// données encodées dans le token
userId: userData.id,
isAdmin: userData.isAdmin,
},
// clé secrète pour l'encodage
process.env.JWT_SIGN_SECRET,
{
// durée de validité du token
expiresIn: "1h",
},
);
},
parseAuthorization: function (authorization) {
// récupération du token
return authorization != null ? authorization.replace("Bearer ", "") : null;
},
getUserid: function (authorization) {
// récupération de l'ID utilisateur
const jwttoken = module.exports.parseAuthorization(authorization);
console.log(jwttoken);
if (jwttoken != null) {
try {
// vérification du token
const jwtToken = jwt.verify(jwttoken, process.env.JWT_SIGN_SECRET);
if (jwtToken && jwtToken.userId) {
// si le token est valide, on retourne l'ID utilisateur
return jwtToken.userId;
} else {
// Sinon, renvoyez une erreur
throw new Error("ID d'utilisateur manquant dans le jeton JWT");
}
} catch (err) {
// Sinon, renvoyez une erreur
throw new Error("Erreur de vérification du jeton utilisateur");
}
} else {
throw new Error("Jetons identification non valides");
}
},
generateTemporaryToken: function (userId) {
return jwt.sign(
{
userId: userId,
// Autres données éventuelles
},
process.env.TEMPORARY_TOKEN_SECRET, // Clé secrète spécifique pour les tokens temporaires
{
expiresIn: "15m", // Durée de validité du token temporaire (30 minutes)
},
);
},
parseTemporaryToken: function (temporaryToken) {
// récupération du token
return temporaryToken != null
? temporaryToken.replace("Bearer ", "")
: null;
},
};
The AuthContext file where I store the information:
// src/context/AuthContext.js
// Importation des dépendances nécessaires
import React, { createContext, useState } from 'react';
// Création du contexte d'authentification
export const AuthContext = createContext();
// Composant fournisseur du contexte d'authentification
export const AuthProvider = ({ children }) => {
// État pour suivre si l'utilisateur est connecté ou non
const [isUserLoggedIn, setUserLoggedIn] = useState(false);
const [userId, setUserId] = useState(null);
const [userPseudo, setUserPseudo] = useState(null);
const [userData, setUserData] = useState(null);
const [userToken, setUserToken] = useState(null);
// Fonction pour connecter l'utilisateur
const login = async (user) => {
const userToken = await generateTokenForUser(user);
localStorage.setItem('userToken', userToken);
setUserLoggedIn(true);
setUserId(user.id);
setUserPseudo(user.pseudo);
setUserToken(userToken);
};
// Fonction pour déconnecter l'utilisateur
const logOut = () => {
//localStorage.removeItem('userToken');
setUserLoggedIn(false);
setUserId(null);
setUserPseudo(null);
setUserData(null);
setUserToken(null);
};
// Fonction pour mettre à jour le pseudo de l'utilisateur
const updateUserPseudo = (pseudo) => {
setUserPseudo(pseudo);
};
// Fonction pour définir l'ID de l'utilisateur dans le contexte d'authentification
const setAuthContextUserId = (id) => {
setUserId(id);
};
// Fournir l'état et les fonctions associées aux composants enfants via le contexte
return (
<AuthContext.Provider value={{
isUserLoggedIn, userId, userPseudo, userData, userToken, setUserToken,
updateUserPseudo, setUserLoggedIn, setUserId, setAuthContextUserId, setUserPseudo, setUserData,
login, logOut }}>
{children}
</AuthContext.Provider>
);
};
Here are the files that require a token: homeLocationctrl:
// importation des modules
const { homelocation } = require("../Models");
const jwt = require("../utils/jwt");
module.exports = {
newlocations: async (req, res) => {
// récupération du header d'authentification
try {
console.log("Nouvelle requête de création de lieu.");
const headerAuth = req.headers["authorization"];
const userId = jwt.getUserid(headerAuth);
console.log("ID de l'utilisateur extrait du token :", userId);
/**
* Finds a user's home location by their user ID.
* @async
* @function
* @param {number} userId - The user ID to search for.
* @returns {Promise<object>} - A Promise that resolves with the user's home location object if found, or null if not found.
*/
const userFound = await homelocation.findOne({
where: { homeID: userId },
});
const { namelocation, infolocation, adresslocation } = req.body;
console.log("Données reçues de la requête :", req.body);
if (!namelocation || !infolocation || !adresslocation) {
console.log("Paramètres manquants.");
return res.status(400).json({ error: "Paramètres manquants" });
}
if (namelocation.length < 5 || namelocation.length > 20) {
console.log("Le nom du lieu ne respecte pas la longueur requise.");
return res.status(400).json({
error: "Le nom du lieu doit être compris entre 5 et 20 caractères",
});
}
if (infolocation.length < 5 || infolocation.length > 350) {
console.log("Les informations ne respectent pas la longueur requise.");
return res.status(400).json({
error:
"Les informations doivent être comprises entre 5 et 350 caractères",
});
}
if (adresslocation.length < 5 || adresslocation.length > 100) {
console.log("L'adresse ne respecte pas la longueur requise.");
return res.status(400).json({
error: "L'adresse doit être comprise entre 5 et 100 caractères",
});
}
homelocation
.create({
homeID: userId,
namelocation,
infolocation,
adresslocation,
})
.then(function (newLocation) {
console.log("Nouvelle location créée :", newLocation);
return res.status(201).json({
locationID: newLocation.homeID,
message: "Nouvelle location créée",
});
})
.catch(function (err) {
console.error("Erreur lors de la création de la location :", err);
return res
.status(500)
.json({ error: "Erreur inattendue : merci de recommencer" });
});
} catch (error) {
console.error("Erreur inattendue :", error);
}
},
// route getlocations
getlocations: async (req, res) => {
console.log("Requête GET reçue pour /api/homelocation/getloc");
try {
console.log("Nouvelle requête pour obtenir les lieux de l'utilisateur.");
const headerAuth = req.headers["authorization"];
console.log("Token reçu depuis le client :", headerAuth);
const userId = jwt.getUserid(headerAuth);
console.log("ID de l'utilisateur extrait du token :", userId);
homelocation
.findAll({
where: { homeID: userId },
})
.then(function (userFound) {
// retour si l'utilisateur existe déjà
if (userFound && userFound.length > 0) {
console.log("Voici les résultats");
return res.status(200).json(userFound);
} else {
console.log("L'utilisateur n'a pas de lieu enregistrer");
return res
.status(404)
.json({ error: "L'utilisateur n'a pas de lieu enregistrer pour le moment" });
}
})
.catch(function (err) {
console.error("Erreur lors de la récupération des lieux :", err);
return res
.status(500)
.json({ error: "Impossible de récupérer les lieux" });
});
} catch (error) {
console.error("Erreur inattendue :", error);
}
},
// route updatelocations
updatelocations: async (req, res) => {
try {
console.log("Nouvelle requête de modification de lieu.");
const headerAuth = req.headers["authorization"];
const userId = jwt.getUserid(headerAuth);
console.log("ID de l'utilisateur extrait du token :", userId);
homelocation
.findOne({
where: { homeID: userId },
})
.then(function (userFound) {
if (userFound) {
userFound
.update({
namelocation: req.body.namelocation,
infolocation: req.body.infolocation,
adresslocation: req.body.adresslocation,
})
.then(function () {
console.log("Location modifié avec succès.");
return res.status(201).json({ message: "Lieu modifié" });
})
.catch((err) => {
console.error("Erreur lors de la modification du lieu :", err);
return res
.status(500)
.json({ error: "Impossible de modifier le lieu" });
});
} else {
return res.status(404).json({ error: "Le lieu n'existe pas" });
}
})
.catch(function (err) {
console.error("Erreur lors de la modification du lieu :", err);
return res
.status(500)
.json({ error: "Impossible de modifier le lieu" });
});
} catch (error) {
console.error("Erreur inattendue :", error);
}
},
// route deletelocations
deletelocations: async (req, res) => {
try {
console.log("Nouvelle requête de suppression de lieu.");
const headerAuth = req.headers["authorization"];
const userId = jwt.getUserid(headerAuth);
console.log("ID de l'utilisateur extrait du token :", userId);
const userFound = await homelocation.findOne({
where: { homeID: userId },
});
if (!userFound) {
console.log("Le lieu n'existe pas.");
return res.status(404).json({ error: "Le lieu n'existe pas" });
}
userFound
.destroy()
.then(function () {
console.log("Lieu supprimé avec succès.");
return res.status(201).json({ message: "Lieu supprimé" });
})
.catch(function (err) {
console.error("Erreur lors de la suppression du lieu :", err);
return res
.status(500)
.json({ error: "Impossible de supprimer le lieu" });
});
} catch (error) {
console.error("Erreur inattendue :", error);
}
},
};
Location:
// src/navigation/location.js
// Importations nécessaires
import { useState, useEffect, useContext } from 'react';
import { View, Text, TouchableOpacity, FlatList, Button } from 'react-native';
import locationStyle from '../styles/locationStyle';
import { AuthContext } from '../contexts/AuthContext';
import { get } from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
function LocationScreen({ route, navigation }) {
const { userId, userToken, userPseudo } = useContext(AuthContext);
const [locations, setLocations] = useState([]);
const [showDeleteButton, setShowDeleteButton] = useState(true);
useEffect(() => {
console.log("Token mis à jour :", userToken);
if (!userId) return;
// Charger les locations depuis l'API
const loadUserLocations = async () => {
console.log("Page Mes Location ID:", userId, "- Username:", userPseudo, "- Token:", userToken)
// Vérifier si le userToken est vide
if (!userToken || userToken.trim() === '') {
console.log("Le token de l'utilisateur est absent ou vide.");
// Ici, tu pourrais renvoyer une erreur ou demander à l'utilisateur de se reconnecter
return; // Arrêter l'exécution si le token n'est pas valide
}
try {
const response = await fetch(`http://192.168.1.17:3000/api/homelocation/getloc?userId=${userId}`, {
headers: {
'Authorization': `Bearer ${userToken}`, // userToken provient de ton AuthContext
'Content-Type': 'application/json'
}
});
console.log('Réponse brute:', response);
// Vérifiez le statut HTTP de la réponse
if (response.ok) {
const data = await response.json();
setLocations(data);
} else {
console.error('Erreur de statut:', response.status);
// Log de la réponse pour le debug
const text = await response.text();
console.log('Réponse brute:', text);
}
} catch (error) {
console.error('Erreur lors du chargement des emplacements', error.message);
}
};
loadUserLocations();
}, [userId]);
useEffect(() => {
if (route.params?.locationTitle && !locations.includes(route.params?.locationTitle)) {
setLocations(prev => [...prev, route.params?.locationTitle]);
}
}, [route.params?.locationTitle]);
// Fonction pour gérer la suppression d'une location
const handleDeleteLocation = async (item) => {
try {
await fetch(`http://192.168.1.17:3000/homelocation/deleteloc`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${userToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: item.id }),
});
setLocations((prevLocations) => prevLocations.filter((location) => location.id !== item.id));
} catch (error) {
console.error('Erreur lors de la suppression de l'emplacement', error);
}
};
return (
<View style={locationStyle.container}>
<Button
title="Ajouter une nouvelle location"
onPress={() => {
navigation.navigate('CreateLocation');
}}
/>
<FlatList
data={locations}
renderItem={({ item }) => (
<View style={locationStyle.listItem}>
<TouchableOpacity
onPress={() => {
navigation.navigate('UiInterface');
}}
>
<Text style={locationStyle.text}>{item.title}</Text>
</TouchableOpacity>
<View style={locationStyle.buttonsContainer}>
<TouchableOpacity
style={locationStyle.button}
onPress={() => {
// Mettre en place la logique de modification ici
}}
>
<Text style={locationStyle.buttonText}>Modifier</Text>
</TouchableOpacity>
{showDeleteButton && (
<TouchableOpacity
style={locationStyle.button}
onPress={() => {
handleDeleteLocation(item);
}}
>
<Text style={{ ...locationStyle.buttonText, color: 'red' }}>Supprimer</Text>
</TouchableOpacity>
)}
</View>
</View>
)}
keyExtractor={(item) => (item.id ? item.id.toString() : Math.random().toString())}
/>
</View>
);
}
export default LocationScreen;
Here are the logs at login:
LOG Code de statut: 200
LOG Données envoyées: {"email": "[email protected]", "password": "Bisous5910*", "username": ""}
LOG Mot de passe envoyé: Bisous5910*
LOG Réponse du serveur: {"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlzQWRtaW4iOmZhbHNlLCJpYXQiOjE2OTkwMDcxNjksImV4cCI6MTY5OTAxMDc2OX0.wQC54F4SkJEIPO4h1ZOtUhuHCBT3Lbf1gAzzliIeED0", "userId": 1, "username": "Zana-S"}
When I click on a button named “My Rentals,” I need to retrieve the rentals created by the user, but to do that, I must retrieve the token that is associated with the ID in the database.
LOG Bouton Mes Location
LOG Token mis à jour : null
LOG Page Mes Location ID: 1 - Username: Zana-S - Token: null
LOG Le token de l'utilisateur est absent ou vide.