العربية

دليل شامل لتطبيق المصادقة في تطبيقات Next.js، يغطي الاستراتيجيات والمكتبات وأفضل الممارسات لإدارة آمنة للمستخدمين.

مصادقة Next.js: دليل تنفيذ كامل

تُعد المصادقة حجر الزاوية في تطبيقات الويب الحديثة. فهي تضمن أن المستخدمين هم من يدّعون أنهم، مما يحمي البيانات ويوفر تجارب مخصصة. تقدم Next.js، بفضل قدراتها على التصيير من جانب الخادم ونظامها البيئي القوي، منصة فعالة لبناء تطبيقات آمنة وقابلة للتطوير. يقدم هذا الدليل شرحًا شاملاً لتنفيذ المصادقة في Next.js، مستكشفًا مختلف الاستراتيجيات وأفضل الممارسات.

فهم مفاهيم المصادقة

قبل الغوص في الشيفرة البرمجية، من الضروري فهم المفاهيم الأساسية للمصادقة:

استراتيجيات المصادقة في Next.js

يمكن استخدام عدة استراتيجيات للمصادقة في Next.js، ولكل منها مزاياها وعيوبها. يعتمد اختيار النهج الصحيح على المتطلبات المحددة لتطبيقك.

1. المصادقة من جانب الخادم باستخدام ملفات تعريف الارتباط (Cookies)

يتضمن هذا النهج التقليدي تخزين معلومات الجلسة على الخادم واستخدام ملفات تعريف الارتباط للحفاظ على جلسات المستخدم على العميل. عندما يقوم المستخدم بالمصادقة، يقوم الخادم بإنشاء جلسة وتعيين ملف تعريف ارتباط في متصفح المستخدم. تتضمن الطلبات اللاحقة من العميل ملف تعريف الارتباط، مما يسمح للخادم بتحديد هوية المستخدم.

مثال على التنفيذ:

لنوضح مثالاً أساسيًا باستخدام `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: 'Login successful' }); } else { res.status(401).json({ message: 'Invalid credentials' }); } } else { res.status(405).json({ message: 'Method not allowed' }); } } ```

ب) الواجهة الأمامية (مكون تسجيل الدخول):

```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('Login failed'); } }; 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

Loading...

; // أو حالة تحميل أكثر سهولة في الاستخدام } return (

Welcome to your Profile!

This is a protected page.

); } 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 }); } } ```

المزايا:

العيوب:

2. المصادقة عديمة الحالة باستخدام JWTs

توفر رموز JWT آلية مصادقة عديمة الحالة. بعد مصادقة المستخدم، يصدر الخادم رمز JWT يحتوي على معلومات المستخدم ويوقعه بمفتاح سري. يخزن العميل رمز JWT (عادةً في التخزين المحلي أو ملف تعريف الارتباط) ويدرجه في ترويسة `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: 'Invalid credentials' }); } } else { res.status(405).json({ message: 'Method not allowed' }); } } ```

ب) الواجهة الأمامية (مكون تسجيل الدخول):

```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); // تخزين الرمز في التخزين المحلي router.push('/profile'); } else { alert('Login failed'); } }; 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

Loading...

; } return (

Welcome to your Profile!

This is a protected page.

); } export default ProfilePage; ```

المزايا:

العيوب:

3. المصادقة باستخدام NextAuth.js

NextAuth.js هي مكتبة مصادقة مفتوحة المصدر مصممة خصيصًا لتطبيقات Next.js. إنها تبسط تنفيذ المصادقة من خلال توفير دعم مدمج لمختلف مقدمي الخدمات (مثل Google و Facebook و GitHub والبريد الإلكتروني/كلمة المرور) وإدارة الجلسات ومسارات API الآمنة.

مثال على التنفيذ:

يوضح هذا المثال كيفية دمج NextAuth.js مع مزود خدمة Google.

أ) تثبيت 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 ( <> Signed in as {session.user.email}
) } else { return ( <> Not signed in
) } } ```

المزايا:

العيوب:

4. المصادقة باستخدام Firebase

تقدم Firebase مجموعة شاملة من الأدوات لبناء تطبيقات الويب والجوال، بما في ذلك خدمة مصادقة قوية. تدعم مصادقة Firebase طرق مصادقة مختلفة، مثل البريد الإلكتروني/كلمة المرور، ومقدمي الخدمات الاجتماعيين (Google، Facebook، Twitter)، والمصادقة برقم الهاتف. تتكامل بسلاسة مع خدمات 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('Signup successful!'); } 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 الخاصة بك على المدى الطويل.