Ricerca nel sito web

Implementazione dell'autenticazione utente nelle app Express


Puoi proteggere gli utenti autentici da quelli dannosi autenticandoli. Assicurati di utilizzare le migliori pratiche per evitare di lasciare buchi di sicurezza.

L'autenticazione utente è il processo di verifica dell'identità di un utente che tenta di accedere alla tua applicazione. Implica l'autorizzazione e il trasferimento delle credenziali per confermare l'autenticità di un utente.

Puoi implementare un semplice modello di autenticazione utente in Node.js utilizzando Express, Bcrypt e MongoDB, in pochi passaggi.

Passaggio 1: configurazione dell'ambiente di sviluppo

Innanzitutto, crea una cartella di progetto e cd al suo interno eseguendo:

mkdir user-authentication
cd user-authentication

Successivamente, inizializza npm nella directory del tuo progetto eseguendo:

npm init -y

Il flag -y inizializza npm e crea il tuo file package.json con tutte le sue impostazioni predefinite.

Questo modello di autenticazione utente richiede alcune dipendenze.

Loro includono:

  • Express: Express è un framework Node.js che fornisce un solido set di funzionalità per applicazioni web e mobili. Semplifica la creazione di applicazioni backend con Node.js.
  • Bcrypt: bcrypt è un pacchetto npm che implementa la funzione di hashing della password bcrypt. Ti consente di creare hash da semplici stringhe di password.
  • Mongoose: Mongoose è una libreria di modellazione dei dati degli oggetti MongoDB. Semplifica le interazioni tra la tua app e un database MongoDB.
  • dotenv: dotenv è un pacchetto a dipendenza zero che carica le variabili di ambiente da un file .env in process.env.
  • Validatore: validatore è un pacchetto che contiene varie funzioni di convalida delle stringhe.
  • Body-parser: il pacchetto body-parser analizza i corpi delle richieste in un middleware prima dei gestori.

Installa i pacchetti eseguendo:

npm install express bcrypt mongoose dotenv validator body-parser

Successivamente, crea un file app.js nella directory principale del tuo progetto e aggiungi il blocco di codice seguente per creare un server Express di base:

// app.js
const express = require('express');
const app = express();
const bodyParser = require("body-parser");
 
const port = 3000;
 
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
 
app.listen(port, ()=>{
    console.log(`App is listening on port ${port}`);
});

Questo codice crea un'istanza dell'applicazione Express chiamando la funzione Express. Utilizza quindi il middleware body-parser per analizzare i corpi delle richieste in arrivo. Quindi inizia ad ascoltare il traffico sulla porta 3000 chiamando il metodo di ascolto dell'istanza Express e passando la variabile port come argomento.

Passaggio 2: connessione dell'applicazione a un database

Nella directory principale del tuo progetto, crea un file .env e memorizza al suo interno le tue credenziali MongoDB. Ciò evita di esporre le credenziali del database in codice che può consentire a utenti malintenzionati di accedere al database.

Successivamente, vai al tuo file app.js e importa mongoose:

const mongoose = require("mongoose");

Quindi, chiama import dotenv e chiama il metodo config su di esso:

require("dotenv").config();

La chiamata al metodo config su dotenv carica le variabili ambientali in process.env.

Infine, chiama il metodo connect su mongoose e passa il tuo URI MongoDB come argomento:

mongoose.connect(process.env.MONGODB_URI).then(() => {
    console.log('Connected to Database Successfully')
})

Passaggio 3: creazione del modello utente

Nella directory principale del tuo progetto, crea una cartella "models"; qui è dove memorizzerai il tuo modello di mangusta:

mkdir models

Successivamente, crea un file "userModel" e aggiungi le seguenti importazioni:

const mongoose = require('mongoose')
const { isEmail } = require('validator')

isEmail è una funzione di convalida che restituisce true se una determinata stringa è un'e-mail. Ne avrai bisogno per applicare la convalida Mongoose al tuo modello utente.

Successivamente, aggiungi il seguente codice al tuo file userModel:

// models/userModel
const userSchema = mongoose.Schema({
    email: {
        type: String,
        required: [true, 'Email is required'],
        validate: {
            validator: isEmail,
            message: props => `${props.value} is not a valid email`
        }
    },
 
    password: {
        type: String,
        required: [true, 'Password is required'],
        validate: {
            validator: function (value) {
                return value.length >= 6
            },
            message: () => 'Password must be at least six characters long'
        }
    }
})
 
module.exports = mongoose.model('User', userSchema)

Il codice sopra crea una variabile userSchema che memorizza il valore del metodo mongoose.Schema. Il metodo mongoose.Schema associa le proprietà a una raccolta MongoDB e definisce la forma dei documenti al suo interno. Lo schema mongoose ha due proprietà, un'email e una password, che costituiranno i tuoi requisiti di autenticazione.

La proprietà email è di tipo stringa e richiesto è impostata su true. Se il corpo della richiesta non contiene una proprietà email, verrà visualizzato il messaggio di errore di accompagnamento "E-mail obbligatoria". Infine, utilizzando la convalida personalizzata Mongoose, la proprietà validator fa riferimento alla funzione isEmail. Quella funzione restituisce vero o falso in base alla validità della stringa come email. Quindi la proprietà message prende il valore email (props) e costruisce un messaggio di errore significativo.

La proprietà password è un tipo di stringa obbligatoria con un messaggio di errore che dice "È richiesta la password". La funzione validatore è anonima e restituisce true se la password è lunga almeno sei caratteri.

La riga finale crea ed esporta un modello mongoose chiamando il metodo model su mongoose. Passa il nome del modello (Utente) come primo argomento e uno schema (userSchema) come secondo argomento.

Passaggio 4: implementazione dei percorsi di accesso e registrazione

Nella directory principale del tuo progetto, crea una cartella routes:

mkdir routes

Nella cartella dei percorsi, crea un file userRoutes.js e aggiungi le seguenti importazioni:

// routes/userRoutes.js
const express = require("express");
const User = require("../models/userModel");
const bcrypt = require("bcrypt");

Crea un'istanza Express Router chiamando il metodo Router su express:

const router = express.Router();

Successivamente, crea il tuo percorso di registrazione aggiungendo il blocco di codice seguente al tuo file userRoute.js:

router.post("/sign-up", async (req, res) => {
  try {
    // Extract email and password from the req.body object
    const { email, password } = req.body;
    
    // Check if the email is already in use
    let userExists = await User.findOne({ email });
 
    if (userExists) {
      res.status(401).json({ message: "Email is already in use." });
      return;
    }
 
    // Define salt rounds
    const saltRounds = 10;
 
    // Hash password
    bcrypt.hash(password, saltRounds, (err, hash) => {
      if (err) throw new Error("Internal Server Error");
 
      // Create a new user
      let user = new User({
        email,
        password: hash,
      });
 
      // Save user to database
      user.save().then(() => {
        res.json({ message: "User created successfully", user });
      });
    });
  } catch (err) {
    return res.status(401).send(err.message);
  }
});

Nel blocco di codice sopra, per prima cosa hai destrutturato l'e-mail e la password dall'oggetto req.body. Quindi, controlla se un utente sta già utilizzando l'e-mail perché dovrebbe essere univoca per ciascun utente. Se l'e-mail è già stata utilizzata, restituisci e interrompi l'esecuzione del codice con un codice di stato 401.

L'archiviazione di password semplici in un database rappresenta un'enorme minaccia alla sicurezza poiché gli hacker malintenzionati potrebbero accedere al database. Dovresti eseguire l'hashing delle password prima di inserirle nel tuo database, quindi anche se un hacker le scopre, non ci dovrebbero essere rischi per gli utenti. L'hashing è il processo di conversione di una determinata "chiave" in un altro valore. L'hashing è una funzione unidirezionale, il che significa che non è possibile recuperare il valore originale da quello con hash, a differenza della crittografia.

Usando bcrypt, hai sottoposto ad hashing la tua password utente chiamando il metodo hash su bcrypt. Il metodo hash accetta tre parametri: la stringa da sottoporre ad hashing, i salt round e una funzione di callback. Passi la password dell'utente, la variabile saltRounds creata in precedenza e un callback.

I salt round si riferiscono al tempo necessario per calcolare un singolo hash bcrypt. Maggiore è il numero di giri di sale, maggiore sarà il numero di giri di hashing.

Se il metodo hash genera un errore, viene generato un "errore interno del server". Altrimenti, imposti la proprietà password sull'hash corretto e la salvi nel tuo database chiamando il metodo di salvataggio sull'istanza Utente.

Successivamente, crea il tuo percorso di accesso aggiungendo il blocco di codice seguente al tuo file userRoute.js:

router.post("/sign-in", async (req, res) => {
  try {
    // Extract email and password from the req.body object
    const { email, password } = req.body;
 
    // Check if user exists in database
    let user = await User.findOne({ email });
 
    if (!user) {
      return res.status(401).json({ message: "Invalid Credentials" });
    }
 
    // Compare passwords
    bcrypt.compare(password, user.password, (err, result) => {
      if (result) {
        return res.status(200).json({ message: "User Logged in Successfully" });
      }
      
      console.log(err);
      return res.status(401).json({ message: "Invalid Credentials" });
    });
  } catch (error) {
    res.status(401).send(err.message);
  }
});
 
module.exports = router;

Nel blocco di codice sopra, per prima cosa destruttura l'e-mail e la password dall'oggetto req.body. Quindi, controlla se esiste un utente nel tuo database. Se l'utente non esiste nel tuo database, ritorni con un codice di stato 401.

Successivamente, utilizzando il metodo di confronto di bcrypt, passa la password fornita dall'utente e la password con hash che hai recuperato dal tuo database. Confronta i due per confermare se corrispondono. Se le password corrispondono, restituisci un codice di stato 200 e un messaggio di successo. Altrimenti restituisci un codice di stato 401 e un messaggio di errore.

Infine, importa il router nel tuo file app.js e utilizzalo come middleware a livello di applicazione.

Ciò completa il modello di autenticazione dell'utente; ora gli utenti possono registrarsi e accedere in modo sicuro alla tua applicazione.

L'importanza dell'autenticazione dell'utente

L'autenticazione utente garantisce che solo gli utenti legittimi possano accedere alla tua applicazione. Se i tuoi dati sono in qualche modo personali o privati, dovresti adottare misure per impedire l'accesso a utenti non autenticati.

Articoli correlati: