Rumah > hujung hadapan web > tutorial js > Cara yang Betul untuk melakukan Pengesahan dalam Node.js [uide]

Cara yang Betul untuk melakukan Pengesahan dalam Node.js [uide]

Barbara Streisand
Lepaskan: 2024-12-12 20:08:17
asal
639 orang telah melayarinya

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

Pengesahan ialah salah satu aspek pembangunan bahagian belakang yang paling kritikal namun sering disalahfahamkan. Disebabkan kerumitannya, pembangun kerap beralih kepada penyelesaian pihak ketiga seperti Auth0 atau Supabase. Walaupun ini adalah alat yang sangat baik, membina sistem pengesahan anda sendiri boleh memberikan fleksibiliti dan kawalan yang lebih besar.

Dalam panduan ini, anda akan belajar cara melaksanakan perisian tengah pengesahan mudah untuk perkhidmatan API Express.js anda dengan kebergantungan yang minimum. Pada akhirnya, anda akan mempunyai:

  • Pengesahan kata laluan nama pengguna berfungsi sepenuhnya.
  • Integrasi dengan PostgreSQL untuk menyimpan akaun pengguna.
  • Perisian tengah pengesahan berasaskan JWT.
  • Segarkan semula token dengan Pengesanan Penggunaan Semula Automatik untuk keselamatan yang dipertingkatkan.

Panduan ini memfokuskan pada kesederhanaan dan mengelakkan penggunaan pakej seperti passport.js untuk mengurangkan kerumitan.


Menyediakan Jadual Akaun Pengguna

Pertama, buat jadual PostgreSQL untuk menyimpan akaun pengguna:

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()
);
Salin selepas log masuk

Perisian Tengah Pengesahan JWT

Seterusnya, cipta perisian tengah pengesahan JWT untuk melindungi titik akhir API. Contoh ini menggunakan penyulitan simetri. Untuk seni bina perkhidmatan mikro, pertimbangkan untuk menggunakan penyulitan asimetri dengan pasangan kunci awam/peribadi.

Kod 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;
};
Salin selepas log masuk

Gunakan perisian tengah untuk menjamin laluan:

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

router.get("/user", protectedRoute, async (req, res, next) => {
  const user = req.user!;
  res.json({ user });
});
Salin selepas log masuk

Mencipta Pengawal Pengesahan

Sekarang, laksanakan pengawal untuk pendaftaran dan log masuk:

Pengawal Pendaftaran:

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 };
};
Salin selepas log masuk

Pengawal Log Masuk:

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();
};
Salin selepas log masuk

Menyimpan Token Segar Semula

Token muat semula memberikan pengesahan jangka panjang. Mari buat jadual pangkalan data untuk menyimpannya:

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()
);
Salin selepas log masuk

Penjana Token:

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;
};
Salin selepas log masuk

Muat semula Logik Token:

Laksanakan logik untuk mengendalikan token yang menyegarkan dengan selamat:

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();
  }
};
Salin selepas log masuk

Ketahui lebih lanjut tentang token muat semula dan Pengesanan Penggunaan Semula Automatik dalam artikel Auth0 ini.


Kesimpulan

Dengan mengikuti panduan ini, anda telah membina sistem pengesahan yang mudah dan selamat untuk API Node.js anda dengan kebergantungan yang minimum. Pendekatan ini memastikan anda mempunyai kawalan penuh dan mematuhi amalan terbaik moden untuk keselamatan.

Jika anda ingin menjimatkan masa dan usaha, lihat Vratix. CLI sumber terbuka kami boleh menyediakan projek Node.js yang berfungsi sepenuhnya dengan pengesahan dalam beberapa saat. Terokai modul pengesahan kami yang dilaksanakan sepenuhnya di GitHub.


Adakah panduan ini membantu anda? Beritahu kami dalam ulasan atau berhubung dengan kami di X!

Atas ialah kandungan terperinci Cara yang Betul untuk melakukan Pengesahan dalam Node.js [uide]. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan