ویژگی تصویر

استفاده از Passport.js در Node.js — راهنمای جامع

  /  Node.js   /  استفاده از Passport.js در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

Passport.js یک کتابخانه سبک و انعطاف‌پذیر برای پیاده‌سازی احراز هویت در برنامه‌های Node.js است. این ماژول با مفهوم «استراتژی‌ها» کار می‌کند؛ به‌عبارت دیگر هر روش احراز هویتی (مانند لاگین محلی، توکن JWT، OAuth با گوگل یا فیسبوک) به‌صورت یک استراتژی جداگانه اضافه می‌شود. در این مقاله به صورت عملی و با مثال کد نحوه راه‌اندازی، بهترین استفاده‌ها و نکات امنیتی مرتبط با Passport.js را بررسی می‌کنیم.

چرا از Passport.js استفاده کنیم؟

  • سادگی و پلاگین‌محور بودن: اضافه‌کردن انواع استراتژی‌ها آسان است.
  • یکپارچگی با Express و سایر چارچوب‌ها.
  • قابلیت هم‌زمان استفاده از چند استراتژی (مثلاً JWT برای API و Session برای وب).

مراحل کلی راه‌اندازی

  • نصب پکیج‌ها: passport، passport-local یا passport-jwt و express-session
  • پیکربندی استراتژی‌ها (verify callback)
  • serializeUser و deserializeUser در صورت استفاده از session
  • استفاده از middleware در مسیرها

نمونه: راه‌اندازی Local Strategy با bcrypt

const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bcrypt = require('bcrypt');
const users = []; // مثال: در عمل از دیتابیس استفاده کنید

passport.use(new LocalStrategy(async (username, password, done) => {
  const user = users.find(u => u.username === username);
  if (!user) return done(null, false, { message: 'Incorrect username.' });
  const match = await bcrypt.compare(password, user.passwordHash);
  if (!match) return done(null, false, { message: 'Incorrect password.' });
  return done(null, user);
}));

passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => {
  const user = users.find(u => u.id === id);
  done(null, user || null);
});

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());

app.post('/login', passport.authenticate('local', {
  successRedirect: '/profile',
  failureRedirect: '/login'
}));

app.get('/profile', (req, res) => {
  if (!req.isAuthenticated()) return res.redirect('/login');
  res.send(`Hello ${req.user.username}`);
});

توضیح: این کد یک استراتژی محلی را با bcrypt برای مقایسه هش‌های رمز عبور پیاده می‌کند. serializeUser و deserializeUser برای نگهداری نشست‌ها در session استفاده می‌شوند. نکته عملی: در پروژه واقعی کاربران را در دیتابیس ذخیره کنید و مقدار secret برای session را امن نگه دارید.

استفاده از JWT با Passport

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const jwtOptions = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: 'your_jwt_secret'
};

passport.use(new JwtStrategy(jwtOptions, (payload, done) => {
  // payload شامل اطلاعاتی است که هنگام تولید توکن قرار داده‌اید
  const user = users.find(u => u.id === payload.sub);
  if (user) return done(null, user);
  return done(null, false);
}));

// حفاظت از مسیر API
app.get('/api/secure', passport.authenticate('jwt', { session: false }), (req, res) => {
  res.json({ msg: 'Protected data', user: req.user });
});

توضیح: در این مثال از passport-jwt استفاده شده تا توکن JWT از هدر Authorization استخراج و اعتبارسنجی شود. برای APIهای بدون state معمولاً session غیرفعال است (session: false). توصیه: از secret قوی یا کلیدهای عمومی/خصوصی برای RS256 استفاده کنید.

مثال: OAuth با Google

const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
  clientID: GOOGLE_CLIENT_ID,
  clientSecret: GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
  // پیدا کردن یا ساخت کاربر بر پایه profile.id
  let user = users.find(u => u.googleId === profile.id);
  if (!user) {
    user = { id: users.length+1, googleId: profile.id, displayName: profile.displayName };
    users.push(user);
  }
  return done(null, user);
}));

app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
app.get('/auth/google/callback', passport.authenticate('google', {
  successRedirect: '/profile',
  failureRedirect: '/login'
}));

توضیح: این کد روند OAuth با گوگل را نشان می‌دهد: کاربر به صفحه‌ی ورود گوگل هدایت می‌شود و پس از موفقیت به callback مشخص‌شده بازگردانده می‌شود. در callback می‌توانید کاربر را در دیتابیس ایجاد یا بازیابی کنید.

مقایسه سریع استراتژی‌ها

استراتژیمناسب براینکات
Localلاگین با نام‌کاربری/رمزنیاز به مدیریت رمز و bcrypt
JWTAPI بدون state، موبایلتوکن قابل حمل، نیاز به مدیریت انقضا/ریووک
OAuth (Google/Facebook)ورود اجتماعیامن و راحت برای کاربر، نیاز به ثبت اپ در سرویس‌ها

بهترین شیوه‌ها و نکات عملی

  • هرگز رمز را به‌صورت متن ساده ذخیره نکنید؛ از bcrypt یا argon2 استفاده کنید.
  • برای برنامه‌های چندسرویسی، از JWT یا SSO استفاده کنید و session را در store مثل Redis نگه دارید.
  • ترتیب middlewareها مهم است: ابتدا express-session، سپس passport.initialize() و passport.session().
  • در verify callback هیچ‌گاه اطلاعات حساس (مثل رمز کامل) را در توکن‌ها قرار ندهید.
  • برای OAuth از state برای جلوگیری از CSRF استفاده کنید (passport از این پشتیبانی می‌کند).
  • در محیط تولید، secretها را در متغیر محیطی ذخیره کنید و از HTTPS استفاده نمایید.

اشتباهات رایج و رفع آنها

  • عدم فراخوانی app.use(passport.session()) وقتی از session استفاده می‌شود — باعث عدم کارکرد req.isAuthenticated می‌شود.
  • اعمال middlewareها به‌صورت نادرست — همیشه initialize قبل از session را بررسی کنید.
  • استفاده از secret ساده یا نگهداری توکن‌ها در localStorage بدون تدابیر امنیتی — ریسک XSS و دزدی توکن را افزایش می‌دهد.

جمع‌بندی و چشم‌انداز

Passport.js ابزار قدرتمند و منعطفی است که برای اکثر نیازهای احراز هویت در Node.js مناسب است. انتخاب استراتژی مناسب بسته به نوع اپلیکیشن (وب، API، موبایل) و نیازهای امنیتی متفاوت است. با رعایت بهترین شیوه‌ها، مدیریت امن رمزها و استفاده از session storeهای مقیاس‌پذیر، می‌توانید یک سامانه احراز هویت قابل اعتماد و قابل توسعه بسازید.

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

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