المقدمة
السلام عليكم أيها المطورون والمطورات! فالعالم ديال تطوير الويب الحديث، بناء تطبيقات آمنة، سريعة، وفعالة هو الأساس اللي كتوقف عليه تجربة المستخدم الناجحة. فاش كنهضرو على Backend قوي ومعتمد، Laravel كيبان كحل مثالي بفضل سهولة الاستخدام ديالو والقوة ديالو. و باش نخدمو على Frontend عصري، سريع، ومرن، Next.js كيتصدر القائمة بفضل الـReact ودعمو للـServer-Side Rendering (SSR) و Static Site Generation (SSG).
ولكن، كيفاش ممكن ندمجو هاد جوج ديال القوى الكبرى بطريقة احترافية، خصوصًا فجانب المصادقة (Authentication) اللي هو العمود الفقري لأي تطبيق كيحتاج تسجيل الدخول؟ هنا فين كيجي الدور ديال Laravel Sanctum. فهاذ الدليل الشامل، غادي نوريكم خطوة بخطوة كيفاش تخدمو Laravel Sanctum باش تأمنو الـAPI ديالكم، وكيفاش تتواصلو معاه من تطبيق Next.js، باش تبنيو تجربة مستخدم سلسة، آمنة، وموثوقة. الهدف ديالنا هو نوفر ليكم خارطة طريق واضحة باش تبنيو نظام مصادقة كيعتمد على HttpOnly cookies و CSRF protection، وهادشي كامل بالدارجة المغربية باش يكون الفهم أسهل وأوضح.
المحتوى الرئيسي
فهم Laravel Sanctum: مصادقة بسيطة وفعالة
قبل ما نبداو فالجوانب التطبيقية، من الضروري نفهمو شنو هو Laravel Sanctum. Sanctum هو باكج خفيف وسهل الاستخدام كيمكنك من توفير مصادقة API بسيطة وقوية للتطبيقات اللي كتستعمل Single Page Applications (SPAs) بحال Next.js، Mobile Applications، أو حتى Personal Access Tokens. بدل ما تعتمد على JWT (JSON Web Tokens) اللي كتحتاج إدارة معقدة للـtokens فـlocalStorage، Sanctum كيعتمد على Session-based authentication اللي كتستعمل HttpOnly cookies، وهادشي كيعتبر أكثر أمانًا ضد هجمات XSS (Cross-Site Scripting).
الميزات الأساسية ديال Sanctum:
* SPA Authentication: كيوفر طريقة سهلة للمصادقة بين الـSPA والـBackend ديال Laravel، باستعمال HttpOnly cookies و CSRF protection.
* API Token Authentication: كيمكن المستخدمين من يولدوا Personal Access Tokens باش يتصادقو مع الـAPI.
* خفيف وسهل الإعداد: ماشي بحال بعض الحلول الأخرى، Sanctum خفيف ومكيحتاجش بزاف ديال التكوينات.
إعداد Laravel Sanctum فـ Backend ديالك (Laravel)
أول خطوة هي إعداد Laravel Sanctum فالـBackend ديالك.
1. تثبيت Sanctum:
composer require laravel/sanctum
هاد الأمر كيضيف الباكج ديال Sanctum للمشروع ديالك.
2. نشر ملفات التكوين (Configuration) والـMigrations:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
هاد الأمر كيولد ملف config/sanctum.php وكيضيف الـmigrations اللازمة لإنشاء الجداول ديال الـtokens.
3. تشغيل الـMigrations:
php artisan migrate
هاد الأمر كيإنشاء الجداول اللازمة فالقاعدة ديال البيانات، ومن بينها جدول personal_access_tokens.
4. تعديل Kernel.php:
افتح الملف app/Http/Kernel.php وتأكد من أن الـmiddleware ديال EnsureFrontendRequestsAreStateful كاين فمجموعة الـapi middleware. هاد الـmiddleware هو اللي كيخلي Sanctum يعرف أن الطلبات جاية من SPA ويطبق عليها قواعد المصادقة ديال الـsession.
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// ...
// Make sure to uncomment or add it if not present
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
],
5. تكوين CORS (Cross-Origin Resource Sharing):
بما أن الـBackend ديالك (Laravel) والـFrontend ديالك (Next.js) غادي يكونو فـdomains مختلفة، ضروري تكوّن CORS. فتح الملف config/cors.php وعدل عليه:
* 'paths' : تأكد من أن الـAPI routes ديالك مشمولين (مثلاً api/*).
* 'allowed_origins' : ضيف الـURL ديال الـFrontend ديالك (مثلاً http://localhost:3000 فطور التطوير، والـdomain ديال التطبيق ديالك فطور الإنتاج).
* 'supports_credentials' : ضروري دير ليه true باش تمكن الـcookies باش يتصيفطو مع الطلبات.
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_origins' => ['http://localhost:3000', 'https://your-nextjs-app.com'],
'allowed_methods' => ['*'],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
6. تفعيل الـAPI routes:
تأكد من أن الـroutes ديال المصادقة ديالك محمية بالـmiddleware ديال auth:sanctum إذا كنتي كتستعمل الـtokens. ولكن للمصادقة ديال SPA، غالبا ما غاديش تحتاج دير auth:sanctum على الـroutes ديال login و logout مباشرة حيت الـmiddleware ديال EnsureFrontendRequestsAreStateful كيتعامل مع الـsession.
بناء الواجهة الأمامية بـ Next.js
دابا غادي ننتقلو للـFrontend ديالنا بـ Next.js.
1. تثبيت Axios:
npm install axios أو yarn add axios
Axios هو مكتبة باش دير طلبات HTTP، وكتوفر ميزات بحال interceptors اللي كتنفع بزاف.
2. إعداد Axios لـSanctum:
إنشئ instance ديال Axios وخزنو فملف بوحدو (مثلاً lib/axios.js).
// lib/axios.js
import axios from 'axios';
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL, // مثلاً: http://localhost:8000
withCredentials: true, // ضروري باش يتصيفطو الـcookies
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
});
export default api;
3. معالجة CSRF Token:
Sanctum كيستعمل HttpOnly cookies باش يخزن الـsession ID والـCSRF token. قبل ما دير أي طلب ديال POST, PUT, PATCH, أو DELETE، خاصك تجلب الـCSRF token من الـBackend.
أول طلب من الـfrontend خاص يكون لـ /sanctum/csrf-cookie باش يتلقى الـCSRF token. هاد الـtoken كيتم التخزين ديالو فـcookie سميتها XSRF-TOKEN.
// فنقطة الدخول ديال التطبيق ديالك (مثلاً _app.js أو قبل أي طلب مصادقة)
const fetchCsrfToken = async () => {
try {
await api.get('/sanctum/csrf-cookie');
} catch (error) {
console.error('Failed to fetch CSRF cookie:', error);
}
};
// استدعي هاد الـfunction قبل أي طلب مصادقة أو فـuseEffect فـLayout ديالك.
4. دورة المصادقة (Login/Logout):
* Login (تسجيل الدخول):
بعد ما تحصل على الـCSRF cookie، ممكن تصيفط طلب POST لـ /api/login مع البريد الإلكتروني وكلمة المرور.
const login = async (email, password) => {
await fetchCsrfToken(); // تأكد من الحصول على CSRF token
try {
const response = await api.post('/api/login', { email, password });
// هنا ممكن تخزن معلومات المستخدم فالـstate أو الـcontext
return response.data;
} catch (error) {
throw error;
}
};
إذا نجح تسجيل الدخول، Laravel غادي يرجع الـsession cookie (HttpOnly) اللي غادي تخزن تلقائيا فالمتصفح ديال المستخدم.
* Logout (تسجيل الخروج):
باش تسجل الخروج، خاصك تصيفط طلب POST لـ /api/logout.
const logout = async () => {
try {
await api.post('/api/logout');
// هنا خاصك تمسح أي بيانات مستخدم من الـstate أو الـcontext
} catch (error) {
throw error;
}
};
هادشي غادي يحذف الـsession cookie من الـBackend، وبالتالي المستخدم غادي يولي غير مصادق عليه.
5. حماية الـRoutes فـ Next.js:
ممكن تحمي الـroutes ديالك فـNext.js سواء فالـclient-side أو الـserver-side.
* Client-Side Protection (فالـReact components):
استعمل useEffect مع useRouter باش تتحقق من حالة المصادقة قبل ما تعرض المحتوى. إذا المستخدم ماشي مصادق عليه، redirectيه لصفحة تسجيل الدخول.
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useAuth } from '../contexts/AuthContext'; // افترض وجود AuthContext
const ProtectedPage = () => {
const { user, loading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!loading && !user) {
router.push('/login');
}
}, [user, loading, router]);
if (loading || !user) {
return <div>Loading...</div>;
}
return <div>محتوى الصفحة المحمية هنا</div>;
};
* Server-Side Protection (بواسطة getServerSideProps):
هاذي طريقة آمنة أكثر، حيت كتحقق من المصادقة قبل ما الصفحة توصل للمتصفح. ممكن دير طلب للـBackend من getServerSideProps باش تتحقق من المستخدم.
// pages/dashboard.js
import api from '../lib/axios';
export async function getServerSideProps(context) {
try {
const response = await api.get('/api/user', {
headers: context.req ? { cookie: context.req.headers.cookie } : undefined,
});
const user = response.data;
return { props: { user } };
} catch (error) {
context.res.writeHead(302, { Location: '/login' });
context.res.end();
return { props: {} };
}
}
const Dashboard = ({ user }) => {
return (
<div>
<h1>مرحبًا بك، {user.name}</h1>
</div>
);
};
export default Dashboard;
هنا، api.get('/api/user') غادي يصيفط الـcookies الموجودة فالطلب ديال المتصفح (عبر context.req.headers.cookie) للـBackend، و Laravel غادي يحدد واش المستخدم مصادق عليه ولا لا.
إدارة الحالة ديال المصادقة (State Management)
باش تحافظ على بيانات المستخدم وحالة المصادقة ديالو فـFrontend، ممكن تستعملو مكتبات إدارة الحالة. React Context API هو خيار ممتاز للتطبيقات الصغيرة والمتوسطة، وممكن تستعملو Zustand أو Jotai للخفة والفعالية.
مثال بسيط بـ React Context:
إنشئ AuthContext.js اللي كيوفر الـuser و الـlogin و الـlogout functions لجميع الـcomponents.
// contexts/AuthContext.js
import { createContext, useContext, useState, useEffect } from 'react';
import api from '../lib/axios';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadUser = async () => {
try {
const response = await api.get('/api/user');
setUser(response.data);
} catch (error) {
setUser(null);
} finally {
setLoading(false);
}
};
loadUser();
}, []);
const login = async (email, password) => {
setLoading(true);
try {
await api.get('/sanctum/csrf-cookie');
const response = await api.post('/api/login', { email, password });
setUser(response.data.user); // افترض ان الـbackend كيرجع 'user'
return response.data;
} finally {
setLoading(false);
}
};
const logout = async () => {
setLoading(true);
try {
await api.post('/api/logout');
setUser(null);
} finally {
setLoading(false);
}
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
من بعد، غلف التطبيق ديالك بـ<AuthProvider> فـ_app.js، واستعمل useAuth() فأي component باش توصل لحالة المصادقة.
أفضل الممارسات ومعالجة الأخطاء
* التحقق من الأخطاء: تأكدوا من معالجة جميع الأخطاء اللي ممكن تطلع من الـAPI (مثلاً، بيانات تسجيل دخول خاطئة، أخطاء السيرفر) وعرض رسائل واضحة للمستخدم.
* تخزين آمن: دائما استعملوا HttpOnly cookies باش تخزنوا الـsessions. هادشي كيحميهم من هجمات XSS حيت الـJavaScript مكيكونش عندو القدرة باش يوصل لهاد الـcookies.
* تجديد الـSessions: Sanctum كيجدد الـsessions تلقائيا مع كل طلب إذا كان المستخدم مصادق عليه والـsession صالحة. تأكدوا من أن الـsession عندها مدة صلاحية معقولة فـconfig/session.php.
Implementing Real-Time Notifications with Laravel WebSockets + React
دابا من بعد ما أمننا المصادقة ديالنا، ممكن نضيفو ميزات الوقت الفعلي (Real-Time features) لتطبيقنا، بحال الإشعارات الفورية أو تحديثات المحتوى. هنا فين كيجي الدور ديال Laravel WebSockets و React.
Laravel WebSockets هو باكج قوي كيمكنك من تشغيل سيرفر WebSockets خاص بك، متوافق تمامًا مع Echo ديال Laravel. فاش كيكون المستخدم مصادق عليه عبر Sanctum، ممكن تبث (broadcast) أحداث معينة من الـBackend لجميع المستخدمين أو لمستخدمين محددين (Private Channels).
كيفية التكامل:
1. Backend (Laravel):
* تثبيت Laravel WebSockets: ثبت الباكج وتبع خطوات الإعداد ديالو. غدي تحتاج تثبت pusher/pusher-php-server و تكوّن الـconfig/broadcasting.php باش تستعمل الـpusher driver مع الـhost و الـport ديال سيرفر الـWebSockets ديالك.
* Broadcasting Events: فاش كيوقع شي حدث فـBackend ديالك (مثلاً، وصول رسالة جديدة، تحديث حالة طلب)، ممكن تبث إيفنت. ممكن تخصص الـEvent ديالك باش يطبق ShouldBroadcast interface. باش تبث لأشخاص محددين (مثلاً، المستخدم اللي مصادق عليه)، ممكن تستعمل private channels اللي كيعتمدو على هوية المستخدم.
2. Frontend (React/Next.js):
* تثبيت Laravel Echo: npm install laravel-echo pusher-js
* إعداد Echo: فـFrontend ديالك، قم بإنشاء instance ديال Laravel Echo وربطها بسيرفر الـWebSockets ديالك. الأهم هو Auth ديال Echo، اللي خاصو يستعمل نفس الـcookies ديال Sanctum باش يتصادق المستخدم مع الـWebSocket server. Echo كيصيفط الـcookies تلقائيًا إذا withCredentials مفعل.
// lib/echo.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
const echo = new Echo({
broadcaster: 'pusher',
key: process.env.NEXT_PUBLIC_PUSHER_APP_KEY, // الـkey ديالك من config/broadcasting.php
wsHost: process.env.NEXT_PUBLIC_WEBSOCKETS_HOST || window.location.hostname,
wsPort: process.env.NEXT_PUBLIC_WEBSOCKETS_PORT || 6001,
wssPort: process.env.NEXT_PUBLIC_WEBSOCKETS_PORT || 6001,
forceTLS: (process.env.NODE_ENV === 'production'),
disableStats: true,
enabledTransports: ['ws', 'wss'],
authEndpoint: `${process.env.NEXT_PUBLIC_BACKEND_URL}/broadcasting/auth`, // ضروري
auth: {
headers: {
// ممكن تضيف headers إضافية إذا لزم الأمر، ولكن مع withCredentials غالبا ما كتحتاج والو.
},
},
});
export default echo;
* الاشتراك في الـChannels: فاش كيكون المستخدم مصادق عليه، ممكن يستعمل echo.private('App.Models.User.' + userId) باش يشترك فالـchannel الخاصة به، ويستقبل الإشعارات اللي كتصيفط ليه.
// فـReact component
import { useEffect } from 'react';
import { useAuth } from '../contexts/AuthContext';
import echo from '../lib/echo';
const Notifications = () => {
const { user } = useAuth();
useEffect(() => {
if (user) {
echo.private(`App.Models.User.${user.id}`)
.notification((notification) => {
console.log('Received notification:', notification);
// عرض الإشعار للمستخدم
})
.listen('NewMessage', (e) => {
console.log('New message event:', e);
// تحديث UI برسالة جديدة
});
}
return () => {
if (user) {
echo.leave(`App.Models.User.${user.id}`);
}
};
}, [user]);
return (
<div>
<h2>إشعاراتي</h2>
{/* عرض الإشعارات هنا */}
</div>
);
};
هاذ التكامل كيخلي التطبيقات ديالكم أكثر حيوية وتفاعل، وكيعطي تجربة مستخدم أفضل بكثير عن طريق توفير تحديثات فورية.
أهم خلاصات الموضوع (Key Takeaways)
* Laravel Sanctum حل مثالي: كيوفر طريقة بسيطة وآمنة للمصادقة ديال SPA باستعمال HttpOnly cookies و CSRF protection.
* إعداد CORS و CSRF ضروري: باش يكون التواصل بين Next.js و Laravel آمن وفعال، خاصك تكوّن CORS بشكل صحيح وتهتم بالـCSRF tokens.
* HttpOnly cookies هي الأفضل: لتخزين الـsessions بأمان وحمايتهم من هجمات XSS، دائما استعملوا HttpOnly cookies.
* إدارة الحالة فـNext.js: استعمل Context API أو أي مكتبة لإدارة الحالة باش تحافظ على بيانات المستخدم وحالة المصادقة ديالو فـFrontend.
* دمج ميزات الوقت الفعلي: ممكن تزيدو ميزات الوقت الفعلي باستعمال Laravel WebSockets + React لتوفير تجربة مستخدم ديناميكية وتفاعلية مع إشعارات فورية.
الخلاصة
باختصار، دمج Laravel Sanctum مع Next.js كيمكنكم من بناء تطبيقات ويب قوية، آمنة، وذات أداء عالي. من خلال اتباع الخطوات اللي ذكرناها فهاذ الدليل، غادي تكونو قادرين على إنشاء نظام مصادقة احترافي كيوفر تجربة مستخدم رائعة، ويحمي البيانات ديالكم ف نفس الوقت. زد على ذلك، القدرة على دمج Real-Time Notifications باستعمال Laravel WebSockets و React كترفع من مستوى التفاعل ديال التطبيق ديالكم وكتخليه أكثر حيوية. ما تنساوش دائما تتبعوا أفضل الممارسات الأمنية وتبقاو على اطلاع بآخر التحديثات ديال كل من Laravel و Next.js باش تحافظو على التطبيقات ديالكم محمية وفعالة. بالتوفيق فجميع مشاريعكم المستقبلية!
