Zaawansowane Funkcje Express.js: Autoryzacja, Obsługa Plików i Walidacja Danych

Express.js to wszechstronny framework backendowy dla Node.js, często używany do budowania aplikacji webowych i API. Dziś zajmiemy się bardziej zaawansowanymi tematami, które pomogą w tworzeniu bezpiecznych i funkcjonalnych aplikacji. Obejrzymy: autoryzację i autentykację z JWT, upload plików z Multerem, oraz walidację danych za pomocą express-validator.

Autoryzacja i Autentykacja

Wprowadzenie do JWT

JWT (JSON Web Tokens) jest popularnym sposobem autentykacji użytkowników w aplikacjach webowych. Token JWT jest kryptograficznie zabezpieczonym ładunkiem danych, który można przekazać między klientem a serwerem, aby sprawdzić autoryzację. Składa się z trzech części:

  1. Nagłówek (Header) – zawiera informacje o algorytmie szyfrowania.
  2. Ładunek (Payload) – przechowuje dane o użytkowniku.
  3. Podpis (Signature) – używany do weryfikacji integralności tokena.

Aby zainstalować JWT w Express.js, użyjemy biblioteki jsonwebtoken:

				
					npm install jsonwebtoken bcryptjs

				
			

bcryptjs jest narzędziem do szyfrowania haseł.

Implementacja Systemu Rejestracji i Logowania

Najpierw utworzymy dwa endpointy: jeden do rejestracji użytkownika, a drugi do logowania.

Rejestracja Użytkownika

				
					const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('./models/User'); // Zakładamy, że mamy model User

const router = express.Router();

// Rejestracja użytkownika
router.post('/register', async (req, res) => {
  try {
    const { username, password } = req.body;

    // Hashowanie hasła
    const hashedPassword = await bcrypt.hash(password, 10);

    // Tworzenie nowego użytkownika
    const user = new User({ username, password: hashedPassword });
    await user.save();

    res.status(201).json({ message: 'Użytkownik zarejestrowany pomyślnie' });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
});

				
			

Logowanie

				
					// Logowanie użytkownika
router.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;

    // Znajdź użytkownika
    const user = await User.findOne({ username });
    if (!user) {
      return res.status(400).json({ message: 'Nieprawidłowa nazwa użytkownika lub hasło' });
    }

    // Sprawdź hasło
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(400).json({ message: 'Nieprawidłowa nazwa użytkownika lub hasło' });
    }

    // Generowanie tokena JWT
    const token = jwt.sign({ id: user._id }, 'sekretnyklucz', { expiresIn: '1h' });
    res.json({ token });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
});

				
			

Middleware do Ochrony Tras

Aby zabezpieczyć dostęp do pewnych tras, możemy stworzyć middleware, który będzie weryfikował token JWT:

				
					// middleware/auth.js
const jwt = require('jsonwebtoken');

const auth = (req, res, next) => {
  const token = req.header('Authorization')?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ message: 'Brak tokena, autoryzacja odrzucona' });
  }

  try {
    const decoded = jwt.verify(token, 'sekretnyklucz');
    req.user = decoded;
    next();
  } catch (error) {
    res.status(401).json({ message: 'Token jest nieprawidłowy' });
  }
};

module.exports = auth;

				
			

Teraz możemy używać tego middleware’u, aby chronić trasy, np.:

				
					const auth = require('./middleware/auth');

router.get('/profile', auth, (req, res) => {
  res.json({ message: 'Dostęp do profilu użytkownika jest chroniony' });
});

				
			

Obsługa Plików

Upload Plików za Pomocą Multer

Multer to middleware, który ułatwia przesyłanie plików w Express.js. Zainstaluj go komendą:

				
					npm install multer

				
			

Tworzymy middleware Multera:

				
					const multer = require('multer');

// Konfiguracja przechowywania plików
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    cb(null, `${Date.now()}-${file.originalname}`);
  },
});

const upload = multer({ storage });

const router = express.Router();

// Endpoint do uploadu plików
router.post('/upload', upload.single('file'), (req, res) => {
  res.json({ message: 'Plik został pomyślnie przesłany', file: req.file });
});

				
			

W tym przykładzie konfigurujemy multer do przechowywania plików w katalogu uploads/, a plik będzie miał unikalną nazwę opartą na aktualnym czasie.

Obsługa Zasobów Statycznych (express.static)

Jeśli chcemy udostępniać publicznie przesłane pliki lub inne zasoby (np. obrazy, CSS, JavaScript), możemy użyć wbudowanego middleware:

				
					app.use('/uploads', express.static('uploads'));

				
			

Dzięki temu każdy plik w katalogu uploads/ będzie dostępny pod adresem http://localhost:3000/uploads/{nazwa_pliku}.

Walidacja Danych

Wprowadzenie do express-validator

express-validator to popularne narzędzie do walidacji danych przychodzących w żądaniach. Aby go zainstalować:

				
					npm install express-validator

				
			

Implementacja Walidacji Danych

Użyjemy express-validator, aby upewnić się, że dane dostarczane przez użytkowników spełniają nasze wymagania. Przykład walidacji przy rejestracji użytkownika:

				
					const { body, validationResult } = require('express-validator');

router.post('/register', [
  body('username').isLength({ min: 5 }).withMessage('Nazwa użytkownika musi mieć co najmniej 5 znaków'),
  body('password').isLength({ min: 8 }).withMessage('Hasło musi mieć co najmniej 8 znaków'),
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }

  // Dalej postępujemy z logiką rejestracji
  try {
    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, password: hashedPassword });
    await user.save();
    res.status(201).json({ message: 'Użytkownik zarejestrowany pomyślnie' });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
});

				
			

W powyższym kodzie walidujemy, czy username ma przynajmniej 5 znaków, a password przynajmniej 8 znaków. Jeśli walidacja się nie powiedzie, zwracamy odpowiedni komunikat.

Podsumowanie

Dziś omówiliśmy bardziej zaawansowane funkcje Express.js, które są kluczowe dla bezpiecznego i funkcjonalnego rozwoju aplikacji:

  1. Autoryzacja i autentykacja z JWT – stworzyliśmy system rejestracji, logowania i ochrony tras.
  2. Obsługa plików z Multerem – przesyłanie plików stało się łatwe dzięki Multer.
  3. Walidacja danych z express-validator – upewniliśmy się, że dane wprowadzane przez użytkowników są poprawne.

Dzięki temu Twoje aplikacje będą bardziej bezpieczne, funkcjonalne i skalowalne.