ویژگی تصویر

ساخت سیستم لاگین و ثبت‌نام با Node.js — راهنمای کامل

  /  Node.js   /  ساخت سیستم لاگین و ثبت نام با Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

در این مقاله قدم‌به‌قدم یک سیستم ثبت‌نام و لاگین (احراز هویت) با Node.js را بررسی می‌کنیم. از طراحی مدل کاربر تا ذخیره ایمن رمزعبور، ایجاد توکن JWT، اعتبارسنجی ورودی و نکات امنیتی مهم را پوشش می‌دهیم. این راهنما برای توسعه‌دهندگان وب که می‌خواهند یک سیستم احراز هویت کاربردی و امن بسازند مناسب است.

پیش‌نیازها و انتخاب‌ها

  • Node.js و npm
  • Express برای سرور HTTP
  • MongoDB + Mongoose برای ذخیره کاربر (می‌توان با SQL هم پیاده کرد)
  • bcrypt برای هش کردن رمزعبور
  • jsonwebtoken برای تولید JWT
  • express-validator یا Joi برای اعتبارسنجی ورودی

معماری ساده

ما از ساختار RESTful استفاده می‌کنیم: دو مسیر اصلی /api/auth/register و /api/auth/login. پس از لاگین، سرویس یک JWT به فرانت‌اند بازمی‌گرداند یا از سشن (session) استفاده می‌کند.

نمونه مدل کاربر با Mongoose

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: { type: String, required: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  password: { type: String, required: true },
  createdAt: { type: Date, default: Date.now },
  isVerified: { type: Boolean, default: false }
});

module.exports = mongoose.model('User', userSchema);

این مدل فیلدهای پایه را تعریف می‌کند: نام، ایمیل، رمزعبور، تاریخ ایجاد و فلگ تایید ایمیل. دقت کنید که ایمیل unique است تا چند ثبت‌نام با یک ایمیل رخ ندهد.

ثبت‌نام — ثبت امن رمزعبور

const express = require('express');
const bcrypt = require('bcrypt');
const User = require('./models/User');
const router = express.Router();

router.post('/register', async (req, res) => {
  try {
    const { name, email, password } = req.body;
    const existing = await User.findOne({ email });
    if (existing) return res.status(400).json({ message: 'Email already in use' });

    const saltRounds = 12;
    const hashed = await bcrypt.hash(password, saltRounds);

    const user = new User({ name, email, password: hashed });
    await user.save();
    res.status(201).json({ message: 'User created' });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

کد بالا ابتدا بررسی می‌کند ایمیل تکراری وجود ندارد، سپس با bcrypt و 12 راند نمک‌زنی رمز را هش کرده و کاربر را ذخیره می‌کند. استفاده از saltRounds بالاتر امنیت را بهتر می‌کند ولی زمان را افزایش می‌دهد.

ورود و تولید JWT

const jwt = require('jsonwebtoken');

router.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    if (!user) return res.status(400).json({ message: 'Invalid credentials' });

    const match = await bcrypt.compare(password, user.password);
    if (!match) return res.status(400).json({ message: 'Invalid credentials' });

    const payload = { id: user._id, email: user.email };
    const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });

    res.json({ token });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

در این بخش، اعتبارسنجی رمز با bcrypt.compare انجام می‌شود. سپس یک JWT با payload ساده ساخته و برگشت داده می‌شود. کلید مخفی (JWT_SECRET) باید در متغیر محیطی ذخیره شود و هرگز در کد منبع قرار نگیرد.

میانی‌افزار محافظت از مسیرها

function authMiddleware(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader) return res.status(401).json({ message: 'No token' });

  const token = authHeader.split(' ')[1];
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ message: 'Invalid token' });
  }
}

این middleware توکن را از هدر Authorization دریافت می‌کند، آن را بررسی می‌کند و در صورت معتبر بودن داده کاربر را به req.user اضافه و اجازه ادامه می‌دهد.

بهینه‌سازی‌ها و نکات امنیتی

  • استفاده از HTTPS در محیط تولید
  • ذخیره secret در متغیر محیطی و استفاده از مدیریت کلید
  • اعمال Rate Limiting برای جلوگیری از حملات بروت‌فورس (مثلاً express-rate-limit)
  • استفاده از Helmet برای تنظیم هدرهای امنیتی
  • اعتبارسنجی ورودی‌ها با Joi یا express-validator برای جلوگیری از حملات تزریق
  • در صورت نیاز به logout، برای JWT می‌توان از لیست سیاه (blacklist) یا کوتاه کردن زمان انقضا استفاده کرد
  • برای تایید ایمیل از ارسال لینک تایید استفاده کنید که حاوی توکن یک‌بارمصرف باشد

مقایسه کوتاه: JWT vs Session

ویژگیJWTSession
مقیاس‌پذیریخوب، بدون ذخیره سیشن سمت سرورنیاز به ذخیره‌سازی سیشن (Redis)
امنیتنیاز به مدیریت blacklist برای logoutقابل کنترل و حذف سمت سرور
استفاده در موبایلمناسب (token-based)نیاز به مکانیزم کوکی/سشن

نمونه بهبود: اعتبارسنجی با express-validator

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

router.post('/register', [
  body('email').isEmail(),
  body('password').isLength({ min: 8 })
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
  // ادامه منطق ثبت‌نام...
});

این قطعه بررسی می‌کند ایمیل معتبر است و رمز حداقل 8 کاراکتر دارد. اعتبارسنجی درست جلوی داده‌های نامناسب و حملات را می‌گیرد.

مثال استفاده واقعی و موارد کاربرد

این سیستم برای سایت‌های مبتنی بر کاربر مانند شبکه‌های اجتماعی، فروشگاه‌های آنلاین و داشبوردهای تحت وب مناسب است. در اپلیکیشن‌های موبایل نیز معمولاً از JWT استفاده می‌شود تا پس از لاگین کاربر توکن را در کلاینت ذخیره و در درخواست‌ها ارسال کند.

خلاصه و نکات نهایی

برای ساخت یک سیستم ثبت‌نام و لاگین با Node.js توجه به امنیت (هش کردن رمز، HTTPS، مدیریت کلید)، اعتبارسنجی ورودی، و انتخاب مناسب بین JWT و سشن ضروری است. افزون بر این، پیاده‌سازی امکاناتی مانند تایید ایمیل، بازنشانی رمز (password reset) و محافظت در برابر حملات بروت‌فورس و CSRF تجربه کاربری و امنیت را بهبود می‌بخشد.

در نهایت، تست‌های واحد و انتشار لاگ‌های مناسب برای تحلیل مشکلات در محیط تولید نقش مهمی در پایداری سیستم دارند.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: