فارسی

راهنمایی جامع برای پیاده‌سازی احراز هویت در اپلیکیشن‌های Next.js، شامل استراتژی‌ها، کتابخانه‌ها و بهترین شیوه‌ها برای مدیریت امن کاربران.

احراز هویت در Next.js: راهنمای کامل پیاده‌سازی

احراز هویت، سنگ بنای اپلیکیشن‌های وب مدرن است. این فرآیند تضمین می‌کند که کاربران همان کسانی هستند که ادعا می‌کنند، از داده‌ها محافظت کرده و تجربه‌های شخصی‌سازی شده را فراهم می‌کند. Next.js، با قابلیت‌های رندر سمت سرور و اکوسیستم قدرتمند خود، پلتفرم توانمندی برای ساخت اپلیکیشن‌های امن و مقیاس‌پذیر ارائه می‌دهد. این راهنما یک بررسی جامع از پیاده‌سازی احراز هویت در Next.js را با کاوش در استراتژی‌های مختلف و بهترین شیوه‌ها ارائه می‌دهد.

درک مفاهیم احراز هویت

قبل از ورود به کد، درک مفاهیم بنیادی احراز هویت ضروری است:

استراتژی‌های احراز هویت در Next.js

استراتژی‌های متعددی برای احراز هویت در Next.js وجود دارد که هر کدام مزایا و معایب خاص خود را دارند. انتخاب رویکرد مناسب به نیازمندی‌های خاص اپلیکیشن شما بستگی دارد.

۱. احراز هویت سمت سرور با کوکی‌ها

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

مثال پیاده‌سازی:

بیایید یک مثال پایه با استفاده از `bcrypt` برای هش کردن رمز عبور و `cookies` برای مدیریت نشست را ترسیم کنیم. توجه: این یک مثال ساده شده است و برای استفاده در محیط پروداکشن به اصلاحات بیشتری نیاز دارد (مانند محافظت در برابر CSRF).

الف) بک‌اند (مسیر API - `/pages/api/login.js`):

```javascript import bcrypt from 'bcryptjs'; import { serialize } from 'cookie'; // پایگاه داده جایگزین (با یک پایگاه داده واقعی جایگزین کنید) const users = [ { id: 1, username: 'testuser', password: bcrypt.hashSync('password123', 10) }, ]; export default async function handler(req, res) { if (req.method === 'POST') { const { username, password } = req.body; const user = users.find((u) => u.username === username); if (user && bcrypt.compareSync(password, user.password)) { const token = 'your-secret-token'; // با یک متد تولید توکن قوی‌تر جایگزین کنید // تنظیم کوکی res.setHeader('Set-Cookie', serialize('authToken', token, { path: '/', httpOnly: true, // از دسترسی سمت کلاینت به کوکی جلوگیری می‌کند secure: process.env.NODE_ENV === 'production', // فقط در محیط پروداکشن از طریق HTTPS ارسال شود maxAge: 60 * 60 * 24, // ۱ روز })); res.status(200).json({ message: 'ورود با موفقیت انجام شد' }); } else { res.status(401).json({ message: 'اعتبارنامه‌ها نامعتبر است' }); } } else { res.status(405).json({ message: 'متد مجاز نیست' }); } } ```

ب) فرانت‌اند (کامپوننت ورود):

```javascript import { useState } from 'react'; import { useRouter } from 'next/router'; function LoginComponent() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, password }), }); if (response.ok) { // به صفحه محافظت‌شده هدایت کن router.push('/profile'); // با مسیر محافظت‌شده خود جایگزین کنید } else { alert('ورود ناموفق بود'); } }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} />
); } export default LoginComponent; ```

ج) مسیر محافظت‌شده (`/pages/profile.js` - مثال):

```javascript import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; function ProfilePage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const router = useRouter(); useEffect(() => { const checkAuth = async () => { const response = await fetch('/api/checkAuth'); // یک مسیر API برای تأیید کوکی ایجاد کنید if (response.status === 200) { setIsAuthenticated(true); } else { router.push('/login'); // در صورت عدم احراز هویت به صفحه ورود هدایت کن } }; checkAuth(); }, [router]); if (!isAuthenticated) { return

در حال بارگذاری...

; // یا یک حالت بارگذاری کاربرپسندتر } return (

به پروفایل خود خوش آمدید!

این یک صفحه محافظت‌شده است.

); } export default ProfilePage; ```

د) مسیر API برای تأیید کوکی (`/pages/api/checkAuth.js`):

```javascript import { parse } from 'cookie'; export default function handler(req, res) { const cookies = parse(req.headers.cookie || ''); const authToken = cookies.authToken; if (authToken === 'your-secret-token') { // توکن را تأیید کنید res.status(200).json({ authenticated: true }); } else { res.status(401).json({ authenticated: false }); } } ```

مزایا:

معایب:

۲. احراز هویت بدون حالت با JWT

JWTها یک مکانیسم احراز هویت بدون حالت را فراهم می‌کنند. پس از احراز هویت کاربر، سرور یک JWT صادر می‌کند که حاوی اطلاعات کاربر است و آن را با یک کلید مخفی امضا می‌کند. کلاینت JWT را (معمولاً در local storage یا یک کوکی) ذخیره کرده و آن را در هدر `Authorization` درخواست‌های بعدی قرار می‌دهد. سرور امضای JWT را برای احراز هویت کاربر تأیید می‌کند بدون اینکه برای هر درخواست نیاز به پرس‌وجو از پایگاه داده داشته باشد.

مثال پیاده‌سازی:

بیایید یک پیاده‌سازی پایه JWT با استفاده از کتابخانه `jsonwebtoken` را نشان دهیم.

الف) بک‌اند (مسیر API - `/pages/api/login.js`):

```javascript import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; // پایگاه داده جایگزین (با یک پایگاه داده واقعی جایگزین کنید) const users = [ { id: 1, username: 'testuser', password: bcrypt.hashSync('password123', 10) }, ]; export default async function handler(req, res) { if (req.method === 'POST') { const { username, password } = req.body; const user = users.find((u) => u.username === username); if (user && bcrypt.compareSync(password, user.password)) { const token = jwt.sign({ userId: user.id, username: user.username }, 'your-secret-key', { expiresIn: '1h' }); // با یک کلید مخفی قوی و مخصوص محیط جایگزین کنید res.status(200).json({ token }); } else { res.status(401).json({ message: 'اعتبارنامه‌ها نامعتبر است' }); } } else { res.status(405).json({ message: 'متد مجاز نیست' }); } } ```

ب) فرانت‌اند (کامپوننت ورود):

```javascript import { useState } from 'react'; import { useRouter } from 'next/router'; function LoginComponent() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, password }), }); if (response.ok) { const data = await response.json(); localStorage.setItem('token', data.token); // توکن را در local storage ذخیره کنید router.push('/profile'); } else { alert('ورود ناموفق بود'); } }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} />
); } export default LoginComponent; ```

ج) مسیر محافظت‌شده (`/pages/profile.js` - مثال):

```javascript import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import jwt from 'jsonwebtoken'; function ProfilePage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const router = useRouter(); useEffect(() => { const token = localStorage.getItem('token'); if (token) { try { const decoded = jwt.verify(token, 'your-secret-key'); // توکن را تأیید کنید setIsAuthenticated(true); } catch (error) { localStorage.removeItem('token'); // توکن نامعتبر را حذف کنید router.push('/login'); } } else { router.push('/login'); } }, [router]); if (!isAuthenticated) { return

در حال بارگذاری...

; } return (

به پروفایل خود خوش آمدید!

این یک صفحه محافظت‌شده است.

); } export default ProfilePage; ```

مزایا:

معایب:

۳. احراز هویت با NextAuth.js

NextAuth.js یک کتابخانه احراز هویت متن‌باز است که به طور خاص برای اپلیکیشن‌های Next.js طراحی شده است. این کتابخانه با ارائه پشتیبانی داخلی برای ارائه‌دهندگان مختلف (مانند گوگل، فیسبوک، گیت‌هاب، ایمیل/رمز عبور)، مدیریت نشست و مسیرهای API امن، پیاده‌سازی احراز هویت را ساده می‌کند.

مثال پیاده‌سازی:

این مثال نحوه ادغام NextAuth.js با ارائه‌دهنده گوگل را نشان می‌دهد.

الف) نصب NextAuth.js:

npm install next-auth

ب) ایجاد مسیر API (`/pages/api/auth/[...nextauth].js`):

```javascript import NextAuth from 'next-auth'; import GoogleProvider from 'next-auth/providers/google'; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], secret: process.env.NEXTAUTH_SECRET, // برای نشست‌های امن الزامی است session: { strategy: "jwt", // از JWT برای نشست‌ها استفاده کنید }, callbacks: { async jwt({ token, account }) { // در هنگام ورود، access_token از OAuth را به توکن اضافه کنید if (account) { token.accessToken = account.access_token } return token }, async session({ session, token, user }) { // ارسال ویژگی‌ها به کلاینت، مانند access_token از یک ارائه‌دهنده session.accessToken = token.accessToken return session } } }); ```

ج) فایل `_app.js` یا `_app.tsx` خود را برای استفاده از `SessionProvider` به‌روز کنید:

```javascript import { SessionProvider } from "next-auth/react" function MyApp({ Component, pageProps: { session, ...pageProps } }) { return ( ) } export default MyApp ```

د) دسترسی به نشست کاربر در کامپوننت‌های خود:

```javascript import { useSession, signIn, signOut } from "next-auth/react" export default function Component() { const { data: session } = useSession() if (session) { return ( <> وارد شده به عنوان {session.user.email}
) } else { return ( <> وارد نشده‌اید
) } } ```

مزایا:

معایب:

۴. احراز هویت با Firebase

Firebase مجموعه جامعی از ابزارها را برای ساخت اپلیکیشن‌های وب و موبایل ارائه می‌دهد، از جمله یک سرویس احراز هویت قوی. Firebase Authentication از روش‌های مختلف احراز هویت مانند ایمیل/رمز عبور، ارائه‌دهندگان اجتماعی (گوگل، فیسبوک، توییتر) و احراز هویت با شماره تلفن پشتیبانی می‌کند. این سرویس به طور یکپارچه با سایر خدمات Firebase ادغام می‌شود و فرآیند توسعه را ساده می‌کند.

مثال پیاده‌سازی:

این مثال نحوه پیاده‌سازی احراز هویت با ایمیل/رمز عبور با Firebase را نشان می‌دهد.

الف) نصب Firebase:

npm install firebase

ب) مقداردهی اولیه Firebase در اپلیکیشن Next.js شما (مثلاً `firebase.js`):

```javascript import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export default app; ```

ج) ایجاد یک کامپوننت ثبت نام:

```javascript import { useState } from 'react'; import { createUserWithEmailAndPassword } from "firebase/auth"; import { auth } from '../firebase'; function Signup() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); try { await createUserWithEmailAndPassword(auth, email, password); alert('ثبت نام با موفقیت انجام شد!'); } catch (error) { alert(error.message); } }; return (
setEmail(e.target.value)} /> setPassword(e.target.value)} />
); } export default Signup; ```

د) ایجاد یک کامپوننت ورود:

```javascript import { useState } from 'react'; import { signInWithEmailAndPassword } from "firebase/auth"; import { auth } from '../firebase'; import { useRouter } from 'next/router'; function Login() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); try { await signInWithEmailAndPassword(auth, email, password); router.push('/profile'); // به صفحه پروفایل هدایت کن } catch (error) { alert(error.message); } }; return (
setEmail(e.target.value)} /> setPassword(e.target.value)} />
); } export default Login; ```

ه) دسترسی به داده‌های کاربر و محافظت از مسیرها: از هوک `useAuthState` یا شنونده `onAuthStateChanged` برای ردیابی وضعیت احراز هویت و محافظت از مسیرها استفاده کنید.

مزایا:

معایب:

بهترین شیوه‌ها برای احراز هویت امن

پیاده‌سازی احراز هویت نیازمند توجه دقیق به امنیت است. در اینجا برخی از بهترین شیوه‌ها برای تضمین امنیت اپلیکیشن Next.js شما آورده شده است:

انتخاب روش احراز هویت مناسب

بهترین روش احراز هویت به نیازمندی‌ها و محدودیت‌های خاص اپلیکیشن شما بستگی دارد. هنگام تصمیم‌گیری، عوامل زیر را در نظر بگیرید:

نتیجه‌گیری

احراز هویت یک جنبه حیاتی از توسعه وب مدرن است. Next.js یک پلتفرم انعطاف‌پذیر و قدرتمند برای پیاده‌سازی احراز هویت امن در اپلیکیشن‌های شما فراهم می‌کند. با درک استراتژی‌های مختلف احراز هویت و پیروی از بهترین شیوه‌ها، می‌توانید اپلیکیشن‌های Next.js امن و مقیاس‌پذیری بسازید که از داده‌های کاربر محافظت کرده و تجربه کاربری عالی ارائه می‌دهند. این راهنما برخی از پیاده‌سازی‌های رایج را بررسی کرد، اما به یاد داشته باشید که امنیت یک زمینه در حال تحول مداوم است و یادگیری مستمر بسیار مهم است. همیشه در مورد آخرین تهدیدات امنیتی و بهترین شیوه‌ها به‌روز بمانید تا امنیت بلندمدت اپلیکیشن‌های Next.js خود را تضمین کنید.