Nella lezione precedente abbiamo implementato un sistema di salvataggio e visualizzazione dei punteggi utilizzando Node.js, Express e MongoDB. Ora, andremo a migliorare ulteriormente l'esperienza del giocatore aggiungendo un sistema di autenticazione. Questa funzionalità permetterà ai giocatori di creare un account, accedere per salvare i propri punteggi personali e visualizzare statistiche personalizzate. Per l'autenticazione utilizzeremo JWT (JSON Web Token), una tecnologia che offre sicurezza e praticità nelle applicazioni web.
Obiettivo: aggiungere autenticazione e profilo utente
- Creazione della registrazione e del login: permettere agli utenti di registrarsi e accedere con una password.
- Utilizzo di JSON Web Token (JWT) per autenticare gli utenti: proteggere le rotte API per salvare e recuperare punteggi.
- Visualizzazione delle statistiche personali: mostrare ai giocatori i loro punteggi personali, permettendo un confronto con la classifica generale.
Creazione delle rotte di registrazione e login
Prima di tutto, aggiungeremo le rotte per registrare nuovi utenti e consentire il login. Creiamo una directory models e aggiungiamo un file User.js per il modello di dati utente.
Modello utente
Ecco il codice del file User.js su models:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username: { type: String, unique: true },
password: String,
scores: [
{ type: mongoose.Schema.Types.ObjectId, ref: 'Score' }
]
});
module.exports = mongoose.model('User', userSchema);
Nel modello User, definiamo username come univoco e password per salvare la password. Abbiamo anche un campo scores, un array di ID che fanno riferimento ai punteggi associati all'utente.
Gestione della password per l'autenticazione
Per la sicurezza delle password, utilizziamo il pacchetto bcrypt per crittografarle prima di salvarle nel database. Installiamo bcrypt:
npm install bcrypt
Rotte di registrazione e login
Aggiungiamo la logica per registrare nuovi utenti e gestire l'accesso in server.js:
// server.js
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('./models/User');
const SECRET_KEY = 'your-secret-key';
// Registrazione
app.post('/api/register', async (req, res) => {
const { username, password } = req.body;
try {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({ username, password: hashedPassword });
await newUser.save();
res.status(201).json({ message: 'Utente registrato con successo!' });
} catch (error) {
res.status(500).json({ error: 'Errore durante la registrazione' });
}
});
// Login
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ error: 'Credenziali non valide' });
}
const token = jwt.sign({ userId: user._id }, SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
} catch (error) {
res.status(500).json({ error: 'Errore durante il login' });
}
});
Il sistema di registrazione salva l'utente con una password crittografata, mentre il login verifica le credenziali e genera un token JWT valido per un'ora. Questo token verrà poi utilizzato per autorizzare l'accesso alle rotte protette.
Utilizzo di JWT per autenticare gli utenti
JWT consente di autenticare e autorizzare le richieste alle API. Dopo aver effettuato il login, il token JWT generato viene inviato con le richieste per accedere alle rotte riservate.
Middleware di autenticazione
Per proteggere le rotte riservate, creiamo un middleware che decodifica il token JWT e verifica l'identità dell'utente.
// server.js
const auth = (req, res, next) => {
const token = req.header('Authorization')?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Accesso negato' });
try {
const decoded = jwt.verify(token, SECRET_KEY);
req.userId = decoded.userId;
next();
} catch (error) {
res.status(400).json({ error: 'Token non valido' });
}
};
Ora possiamo applicare il middleware auth alle rotte che richiedono l'autenticazione, come il salvataggio dei punteggi.
Modifica delle rotte di punteggio per associarle agli utenti
Modifichiamo la rotta di salvataggio dei punteggi in modo che ogni punteggio sia associato all'utente loggato:
// server.js
app.post('/api/scores', auth, async (req, res) => {
try {
const { points } = req.body;
const newScore = new Score({ points });
const savedScore = await newScore.save();
await User.findByIdAndUpdate(req.userId, { $push: { scores: savedScore._id } });
res.status(201).json({ message: 'Punteggio salvato!' });
} catch (error) {
res.status(500).json({ error: 'Errore nel salvataggio del punteggio' });
}
});
Questa modifica garantisce che ogni punteggio sia collegato ad un utente specifico. Gli utenti che effettuano l'accesso possono ora salvare i propri punteggi in modo sicuro.
Visualizzazione delle statistiche personali
Aggiungiamo una rotta che consente di visualizzare i punteggi di un utente loggato, così da permettergli di accedere alle proprie statistiche personali.
// server.js
app.get('/api/my-scores', auth, async (req, res) => {
try {
const user = await User.findById(req.userId).populate('scores');
res.status(200).json(user.scores);
} catch (error) {
res.status(500).json({ error: 'Errore nel recupero dei punteggi' });
}
});
Con la rotta /api/my-scores l'utente può recuperare la lista dei propri punteggi.
Modifiche al frontend
Ora torniamo al frontend React e aggiungiamo le funzioni di registrazione e login. Creiamo un modulo di login e registrazione e modifichiamo il layout dell'app per mostrare le statistiche personali.
La funzione per effettuare il login
Aggiungiamo una funzione per effettuare il login e salvare il token JWT:
import axios from 'axios';
const loginUser = async (username, password) => {
try {
const response = await axios.post('http://localhost:5000/api/login', { username, password });
localStorage.setItem('token', response.data.token);
alert('Login effettuato!');
} catch (error) {
alert('Errore nel login.');
}
};
Questa funzione invia il nome utente e la password e, se le credenziali sono corrette, salva il token JWT nel localStorage.
Visualizzare i punteggi personali
Ora aggiungiamo una funzione per recuperare i punteggi personali:
const fetchMyScores = async () => {
const token = localStorage.getItem('token');
try {
const response = await axios.get('http://localhost:5000/api/my-scores', {
headers: { Authorization: `Bearer ${token}` }
});
setScores(response.data);
} catch (error) {
console.error('Errore nel recupero dei punteggi personali:', error);
}
};
Questa funzione invia il token JWT al server per recuperare i punteggi dell'utente loggato.
Il componente per il profilo utente
Creiamo infine un componente UserProfile per visualizzare il nome dell'utente e i suoi punteggi:
// components/UserProfile.js
import React, { useEffect } from 'react';
const UserProfile = ({ scores }) => (
<div>
<h2>Punteggi Personali</h2>
<ul style={{ listStyleType: 'none' }}>
{scores.map((score, index) => (
<li key={index}>
{score.date}: {score.points} punti
</li>
))}
</ul>
</div>
);
export default UserProfile;
Conclusione
In questa lezione, abbiamo aggiunto una gestione degli utenti al nostro Solitario delle 5 Carte, creando un sistema di registrazione e login con autenticazione JWT. Questo ci ha permesso di associare i punteggi ai singoli utenti e di visualizzare le statistiche personali, aumentando l'interesse e la personalizzazione del gioco.
Nella prossima lezione, esploreremo funzionalità aggiuntive come la possibilità di visualizzare statistiche avanzate, confronti tra giocatori e altre opzioni per migliorare l'esperienza di gioco.
Se vuoi aggiornamenti su Aggiungere autenticazione e profilo utente inserisci la tua email nel box qui sotto: