Maison > interface Web > js tutoriel > La bonne façon de procéder à l'authentification dans Node.js [uide]

La bonne façon de procéder à l'authentification dans Node.js [uide]

Barbara Streisand
Libérer: 2024-12-12 20:08:17
original
638 Les gens l'ont consulté

The Right Way to do Authentication in Node.js [uide]

L'authentification est l'un des aspects les plus critiques, mais souvent mal compris, du développement backend. En raison de sa complexité, les développeurs se tournent fréquemment vers des solutions tierces comme Auth0 ou Supabase. Bien qu'il s'agisse d'excellents outils, la création de votre propre système d'authentification peut offrir une plus grande flexibilité et un plus grand contrôle.

Dans ce guide, vous apprendrez comment implémenter un middleware d'authentification simple pour votre service API Express.js avec un minimum de dépendances. À la fin, vous aurez :

  • Authentification par mot de passe du nom d'utilisateur entièrement fonctionnelle.
  • Intégration avec PostgreSQL pour stocker les comptes utilisateurs.
  • Un middleware d'authentification basé sur JWT.
  • Actualisez les jetons avec la détection automatique de la réutilisation pour une sécurité renforcée.

Ce guide se concentre sur la simplicité et évite d'utiliser des packages comme passeport.js pour réduire la complexité.


Configuration du tableau des comptes d'utilisateurs

Tout d'abord, créez une table PostgreSQL pour stocker les comptes d'utilisateurs :

CREATE TABLE users (
    "id" SERIAL PRIMARY KEY,
    "username" VARCHAR(255) UNIQUE NOT NULL,
    "password" VARCHAR(255) NOT NULL,
    "email" VARCHAR(255) UNIQUE,
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW()
);
Copier après la connexion

Middleware d'authentification JWT

Ensuite, créez un middleware d'authentification JWT pour protéger les points de terminaison de l'API. Cet exemple utilise le chiffrement symétrique. Pour les architectures de microservices, pensez à utiliser le chiffrement asymétrique avec une paire de clés publique/privée.

Code du middleware (/src/middleware/jwt.ts) :

import jwt from "jsonwebtoken";

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY as string; // Randomly generated. Min length: 64 characters

export const protectedRoute: RequestHandler = async (req, _, next) => {
  const authHeader = req.header("authorization");

  if (!authHeader) {
    return next(notAuthenticated());
  }

  const accessToken = authHeader.replace(new RegExp("\b[Bb]earer\s"), "");

  try {
    const { userId } = validateJWT(accessToken);
    const user = await userRepository.getUserById(parseInt(userId));

    if (user) {
      req.user = user;
      next();
    } else {
      next(invalidAccessToken());
    }
  } catch (err) {
    next(invalidAccessToken());
  }
};

const validateJWT = (token: string, verifyOptions?: jwt.VerifyOptions) => {
  const jwtVerifyOptions = Object.assign(
    { algorithms: "HS256" },
    verifyOptions,
    {
      issuer: "yourAPI.com",
      audience: "yourAPI.com:client",
    }
  );
  return jwt.verify(token, JWT_SECRET_KEY, jwtVerifyOptions) as T;
};
Copier après la connexion

Utilisez le middleware pour sécuriser les itinéraires :

import { protectedRoute } from "@/middleware/jwt";

router.get("/user", protectedRoute, async (req, res, next) => {
  const user = req.user!;
  res.json({ user });
});
Copier après la connexion

Création de contrôleurs d'authentification

Maintenant, implémentez des contrôleurs pour l'inscription et la connexion :

Contrôleur d'inscription :

import argon from "argon2";

const signup = async (props) => {
  const { username, password, email } = props;

  await userRepo.getUser(username).then((res) => {
    if (res !== null) throw usernameNotAvailable();
  });

  const hashedPass = await argon.hash(password, {
    timeCost: 2,
    parallelism: 1,
    memoryCost: 19456,
  });

  const newUser = await createUser({
    username,
    hashedPass,
    email,
  });

  const refreshToken = await generateRefreshToken(newUser.userId);
  const accessToken = generateAccessToken(newUser.userId);

  const { password: _, ...userRes } = newUser;
  return { user: userRes, accessToken, refreshToken };
};
Copier après la connexion

Contrôleur de connexion :

const login = async (props) => {
  const { username, password } = props;

  const user = await getUser(username).then((res) => {
    if (res === null) throw invalidLoginCredentials();
    return res;
  });

  const isOk = await argon.verify(user.password, password);

  if (isOk) {
    const refreshToken = await generateRefreshToken(user.userId);
    const accessToken = generateAccessToken(user.userId);

    const { password: _, ...userRes } = user;
    return { user: userRes, accessToken, refreshToken };
  }

  throw invalidLoginCredentials();
};
Copier après la connexion

Stockage des jetons d'actualisation

Les jetons d'actualisation fournissent une authentification à long terme. Créons une table de base de données pour les stocker :

CREATE TABLE refresh_tokens (
    "id" SERIAL PRIMARY KEY,
    "token" UUID NOT NULL DEFAULT gen_random_uuid(),
    "token_family" UUID NOT NULL DEFAULT gen_random_uuid(),
    "user_id" INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    "active" BOOLEAN DEFAULT true,
    "expires_at" TIMESTAMP NOT NULL,
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW()
);
Copier après la connexion

Générateurs de jetons :

import jwt from "jsonwebtoken";

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY as string; // Randomly generated. Min length: 64 characters

const generateAccessToken = (userId: number) => {
  const jwtSignOptions = Object.assign(
    { algorithm: "HS256" },
    {},
    {
      issuer: "yourAPI.com",
      audience: "yourAPI.com:client",
    }
  );
  return jwt.sign({ userId: userId.toString() }, JWT_SECRET_KEY, jwtSignOptions);
};

const generateRefreshToken = async (userId: number, tokenFamily?: string) => {
  const expAt = new Date(new Date().getTime() + 31 * 24 * 60 * 60 * 1000); // Expire in 31 days
  const refreshTokenExp = expAt.toISOString();

  const token = await createTokenQuery({
    userId,
    tokenFamily,
    expiresAt: refreshTokenExp,
  });

  return token;
};
Copier après la connexion

Actualiser la logique du jeton :

Implémentez une logique pour gérer les jetons d'actualisation en toute sécurité :

const refreshToken = async ({ token }: RefreshTokenSchema) => {
  const tokenData = await getRefreshToken(token);

  if (!tokenData) throw forbiddenError();

  const { userId, tokenFamily, active } = tokenData;

  if (active) {
    // Token is valid and hasn't been used yet
    const newRefreshToken = await generateRefreshToken(userId, tokenFamily);
    const accessToken = generateAccessToken(userId);

    return { accessToken, refreshToken: newRefreshToken };
  } else {
    // Previously refreshed token used, invalidate all tokens in family
    await invalidateRefreshTokenFamily(tokenFamily);

    throw forbiddenError();
  }
};
Copier après la connexion

En savoir plus sur les jetons d'actualisation et la détection automatique de la réutilisation dans cet article Auth0.


Conclusion

En suivant ce guide, vous avez créé un système d'authentification simple et sécurisé pour votre API Node.js avec un minimum de dépendances. Cette approche garantit que vous avez un contrôle total et que vous adhérez aux meilleures pratiques modernes en matière de sécurité.

Si vous souhaitez économiser du temps et des efforts, consultez Vratix. Notre CLI open source peut mettre en place un projet Node.js entièrement fonctionnel avec authentification en quelques secondes. Explorez notre module d'authentification entièrement implémenté sur GitHub.


Ce guide vous a-t-il aidé ? Faites-le nous savoir dans les commentaires, ou connectez-vous avec nous sur X !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal