حول المحتوى:
شرح جذور مشكلة CORS، كيفية إعدادها بشكل آمن، الأخطاء الشائعة، ولماذا حله بشكل عشوائي يعرض مشروعك للخطر.
المشكلة: كثير من المطورين عندما يواجهون خطأ CORS في المتصفح يكتبون أول حل يجدونه في StackOverflow: السماح للجميع *، فتح كل الهيدرز، وكل الميثودز… ثم ينسون الموضوع.
هذا الأسلوب قد يحل الخطأ أمامك، لكنه غالبًا يفتح بابًا لمشاكل أمنية خطيرة على مشروعك، خاصة إذا كنت تعمل على API عام أو لوحة تحكم أو مشروع به بيانات حساسة. في هذا المقال سنشرح:
هذا الشرح موجه للمطورين الذين سبق وعملوا مع Django أو FastAPI أو REST APIs، ويريدون فهم جذور مشكلة CORS Django FastAPI بدلًا من حلها عشوائيًا.
CORS اختصار لـ Cross-Origin Resource Sharing، وهي آلية في المتصفح تهدف لحماية المستخدم من أن يقوم موقع معين بطلب بيانات حساسة من موقع آخر بدون إذن.
المتصفح يعرّف origin كالتالي:
إذا كان عندك:
فهما origin مختلفان، حتى لو كانا على نفس الجهاز. عندها يبدأ المتصفح في تطبيق قواعد CORS.
عندما يرسل الجافاسكربت من المتصفح طلبًا إلى API على origin مختلف، المتصفح يتأكد هل هذا الـ API يسمح بمشاركة الموارد مع هذا الـ origin أم لا، عن طريق الهيدرز مثل:
بناءً على هذه الهيدرز، إما يسمح المتصفح بتمرير الرد للـ JavaScript، أو يمنعه ويظهر لك الخطأ الشهير في الـ Console.
بعض الطلبات تعتبرها CORS "خطيرة" أو "معقدة" (مثل POST مع هيدرز مخصصة). في هذه الحالة المتصفح يرسل طلب OPTIONS أولًا يسمى Preflight:
إذا تجاهلت أو منعت طلبات OPTIONS، ستجد نفسك أمام أخطاء CORS حتى لو أضفت Allow-Origin صحيح.
الأغلب يقوم بالتالي:
هذا الخليط قد يؤدي إلى:
تذكر أن CORS ليست نظام صلاحيات معقد، لكنها طبقة حماية في المتصفح، وعندما تفتحها بالكامل فأنت فعليًا تقول: أي موقع في العالم يمكنه استغلال الـ API كما لو كان من نفس الـ frontend الخاص بك.
إذا أردت فهم كيف تتكامل CORS مع مفاهيم أخرى مثل Middleware في Django، يمكنك الاطلاع على مقالنا: شرح طريقة استخدام Middleware في Django مع أمثلة وأفضل الممارسات.
في Django لا توجد CORS بشكل افتراضي، غالبًا ستستخدم مكتبة: django-cors-headers.
قم بتثبيت المكتبة:
pip install django-cors-headers
ثم أضفها إلى INSTALLED_APPS في settings.py:
'corsheaders',
وأضف الـ Middleware في أعلى قائمة MIDDLEWARE (مهم أن تسبق CommonMiddleware):
'corsheaders.middleware.CorsMiddleware',
إذا كنت مهتمًا أكثر بفهم ترتيب وعمل الـ Middleware في Django، راجع هذا الشرح: شرح طريقة استخدام Middleware في Django.
بدلًا من السماح للجميع، استخدم قائمة محددة من الـ origins الموثوقة.
في مرحلة التطوير (Development):
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
CORS_ALLOW_CREDENTIALS = True
بهذا تقول لـ Django: اسمح فقط للـ frontend على هذه العناوين بالوصول مع دعم الـ Cookies أو الـ Authorization header.
في مرحلة الإنتاج (Production):
CORS_ALLOWED_ORIGINS = [
"https://frontend.example.com",
"https://admin.example.com",
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
]
CORS_ALLOW_HEADERS = [
"content-type",
"authorization",
"x-requested-with",
]
ملاحظات مهمة:
corsheaders.middleware.CorsMiddleware في بداية القائمة، قد لا تعمل CORS كما تتوقع، لأن Middlewares أخرى قد تعدل على الرد قبله. في FastAPI، إعداد CORS يتم غالبًا باستخدام CORSMiddleware الجاهز من Starlette.
مثال أساسي:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost:3000",
"http://127.0.0.1:3000",
"https://frontend.example.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=["Authorization", "Content-Type", "X-Requested-With"],
)
هنا تحدد بوضوح:
في التطوير، قد تسمح بـ allow_origins=["*"] مع allow_credentials=False فقط لتسريع العمل، لكن لا تنقل هذا الإعداد للإنتاج.
مثال إعداد للمراحل الأولى:
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
ثم في الإنتاج، استبدله بإعداد صارم مثل المثال السابق.
إذا كان مشروعك يستخدم WebSockets في FastAPI، فلاحظ أن CORS لا تُطبّق بنفس الطريقة على WebSockets، لكنك ما زلت تحتاج لتحديد من يستطيع الاتصال بالسيرفر. يمكنك مراجعة: التعامل مع WebSockets في FastAPI: تطبيق عملي.
من الأخطاء الشائعة أن يكون ملف settings.py في Django أو إعدادات FastAPI موحّدة لكل شيء. الأفضل:
يمكنك مثلًا استخدام متغيرات بيئة (Environment Variables) لتحديد CORS_ALLOWED_ORIGINS أو origins في FastAPI.
إذا كنت تستخدم:
للمزيد حول أنظمة المصادقة في Django وFastAPI، يمكنك الاطلاع على: تنفيذ OAuth2 في Django و FastAPI: دليل عملي كامل.
إذا ظهر خطأ CORS:
بهذا الأسلوب ستفهم أين المشكلة بالضبط بدلاً من تعطيل CORS بالكامل.
http://localhost:3000http://localhost:8000الإعداد المقترح في settings.py:
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
]
CORS_ALLOW_HEADERS = [
"content-type",
"authorization",
"x-requested-with",
]
في React، إذا كنت تستخدم Cookies للجلسات، تأكد من إضافة:
axios.defaults.withCredentials = true;
https://app.example.comhttps://api.example.comإعداد FastAPI:
origins = [
"https://app.example.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True, # إذا كنت تستخدم JWT في Authorization Header فهذه ليست ضرورية عادة
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=["Authorization", "Content-Type"],
)
إذا كنت لا تستخدم Cookies، يمكنك حتى جعل allow_credentials=False لتبسيط الأمور.
مشكلة CORS Django FastAPI ليست "بج" في المتصفح، بل هي طبقة حماية مهمة لحماية المستخدمين من استغلال APIs من مواقع غير موثوقة.
بدل أن:
افعل الآتي:
كل ما زاد وعيك بهذه التفاصيل، زادت جودة وأمان الـ APIs التي تبنيها، وقلّت "الحلول السحرية" التي قد تحل خطأ واحدًا في الـ Console لكنها تفتح أبوابًا كاملة للهجمات على مشروعك.
شرح جذور مشكلة CORS، كيفية إعدادها بشكل آمن، الأخطاء الشائعة، ولماذا حله بشكل عشوائي يعرض مشروعك للخطر.
مساحة اعلانية