خطأ CORS عند الوصول إلى API من تطبيق JavaScript

سيكون هذا إجابة جيدة لي، إلا أنني لا أستطيع جعل المصادقة القائمة على الرؤوس (headers) تعمل، لذا أحاول القيام بذلك عبر النماذج وأواجه أيضًا مشكلة CSRF. هل توجد أي حل؟ أحاول إنشاء موضوع جديد باستخدام واجهة برمجة التطبيقات (API).

سنحتاج إلى مزيد من المعلومات لنتمكن من المساعدة. هل يمكنك مشاركة مقتطف كود يوضح كيفية محاولة استخدام المصادقة القائمة على الرأس؟

المشكلة التي أواجهها تنبع في الغالب من كل محاولة لإجراء اتصال باستخدام المصادقة القائمة على الرؤوس، حيث تكون الرؤوس المقبولة دائمًا “User-Api-Key” و “User-Client-Id” بدلاً من “Api-Key” و “Api-Username”، مما يؤدي إلى أخطاء CORS. لا أعتقد أنني أحتاج إلى مفاتيح قائمة على المستخدمين. أنا أحاول فقط إجراء طلب مصادقة بسيط لإنشاء موضوع جديد. إذا حاولت استخدام “User-Api-Key”، فستظهر لي أخطاء 403.

هذا مثال على الكود (Angular TypeScript)، لكنه يجب أن يكون مشابهًا للإعدادات الأخرى:

    createNewTopic(postBody: any) {
        let url = "myserver.com/posts.json";
        let CATEGORY_ARTICLES = 6;
        let topicContent = `
          <p>بعض المحتوى
        </p>
        <p>هل نجح ذلك؟</p>
        `;
        let post = {
          "title": "اختبار Tdk 1",
          "raw": topicContent,
          "category": CATEGORY_ARTICLES,
          "target_usernames": "tdekoekkoek",
          "archetype": "",
          "created_at": new Date()
        }
        let headers = new HttpHeaders()
          .set("Accept", "application/json")
          .set("User-Api-Key", DISCOURSE_API_KEY)
          .set("User-Key", "system")
          .set("Content-Type", "application/x-www-form-urlencoded")
        let options = {headers: headers};
        return this.http.post(url, post, options);
      }

user-api-key وuser-client-id هما طريقتان مختلفتان تمامًا للمصادقة. مفاتيح واجهة برمجة التطبيقات العادية لن تعمل مع هذه العناوين. ما الذي يحدث عند استخدام أسماء العناوين الصحيحة؟ (api-key وapi-username)

أحصل على خطأ CORS لأن الخادم يتوقع مفتاح API الخاص بالمستخدم. أفحص الرؤوس المتوقعة في استجابة OPTIONS وهذا ما يُذكر فيه. هناك موضوع مشابه آخر في هذا المنتدى حيث واجه مستخدم هذه المشكلة عند الاستدعاء من تطبيق جافا سكريبت.

أوه، إذن تحاول إرسال هذا الطلب من تطبيق جافا سكريبت يعمل على جانب العميل؟ هذا غير مسموح به لعدة أسباب. على سبيل المثال، إذا قمت بتضمين مفتاح واجهة برمجة تطبيقات (API) إداري في كود مصدر تطبيق الجافا سكريبت الخاص بك، فيمكن لأي مستخدم الحصول على وصول إداري كامل إلى المنتدى الخاص بك. إليك موضوعًا سابقًا حول هذا الموضوع.

نعم، هذا ما أحاول فعله. كان ينبغي توثيق ذلك بشكل أوضح. كانت هذه هي استراتيجيتي بالكامل منذ أن بدأت العمل مع Discourse. أقدر مساعدتك. لقد كنت أواجه تحديات في هذا الأمر لعدة أيام وأقرأ الوثائق. سأضطر إلى إعادة التفكير في نهجي بالكامل، حيث أقوم حاليًا ببناء تطبيق خالٍ من الخوادم (serverless)، على الرغم من أنني أملك إمكانية الوصول إلى خادم Node.js.

هذه ليست قيودًا خاصة بـ Discourse - فبشكل عام، يُعد تضمين بيانات اعتماد المسؤول في الكود المصدري لموقع ويب فكرة سيئة.

إذا كان بإمكانك إجراء استدعاء واجهة برمجة تطبيقات Discourse من خادم Node.js الخاص بك، فسيكون ذلك على الأرجح الحل الأفضل. وإذا كنت بحاجة إلى أن يكون تطبيقك من جانب العميل بحتًا، فإن طلب مفاتيح API خاصة بكل مستخدم يُعد خيارًا، على الرغم من أن إعدادها أكثر تعقيدًا بكثير: User API keys specification

بصراحة، يُعد الوصول إلى واجهات برمجة التطبيقات (APIs) من تطبيقات العميل مع تمكين CORS أمرًا شائعًا ومعياريًا للغاية. لا أستطيع تصديق عدم وجود طريقة أكثر أمانًا للقيام بذلك. فكل صناعة تدور حول واجهات برمجة التطبيقات المستضافة التي يتم الوصول إليها من نطاقات مختلفة. أما فيما يتعلق بالوصول باستخدام واجهة برمجة تطبيقات المستخدم، فقد رأيت كيفية إنشاء تلك الواجهات، لكنني غير واضح بشأن ما هي بيانات الاعتماد الفعلية. فأنا دائمًا أحصل على خطأ 403 (مرفوض بسبب عدم وجود إذن) عند استخدام هذه الطريقة.

أعتقد أنني في وضع مماثل.

قليلًا عن حالة الاستخدام:

أستخدم Discourse كواجهة خلفية (backend) وأبني الواجهة الأمامية (frontend) باستخدام VueJS. أعزم على استخدام واجهة برمجة التطبيقات (REST API) فقط. لكل مستخدم في منصتنا، قمت بإنشاء مفتاح API خاص بالمستخدم، وأستخدم كلا الرأسين (Api-Key و Api-Username) للمصادقة.

كل مستخدم يقوم بالمصادقة بشكل آمن مع خوادمنا، ثم يتلقى رمز Discourse الخاص به للمصادقة. بعد ذلك نرغب في استخدام هذا الرمز (في واجهة VueJS الأمامية) لإرسال طلبات API (نشر مواضيع، منشورات، تحرير، إلخ).

لا شيء مشفر بشكل ثابت؛ جميع الرموز تُستلم بعد المصادقة الصحيحة.

المشكلة:
أحصل على رسالة خطأ CORS رغم أنني قمت بتفعيلها في ملف app.yml وضبطتها في قسم الأمان ضمن إعدادات المسؤول.

الخطأ: Request header field api-key is not allowed by Access-Control-Allow-Headers

هل أواجه رسالة خطأ CORS لنفس السبب؟ لماذا تُحجب طلبات CORS عند استخدام رأسّي “Api-Key” و “Api-Username”؟ يجب أن يكون هناك سوء فهم مني لحالة الاستخدام.

تعديل:
لدي نظرية حول سوء فهمي. عندما أنشئ مفتاح API لمستخدم من نقطة نهاية “إنشاء مفتاح API لمستخدم” في واجهة برمجة التطبيقات REST، هل يمتلك هذا المفتاح صلاحيات إدارية؟ أم أنه مجرد مفتاح مستخدم للنشر والتعليق؟ إذا كان الأمر كذلك، فأنا أفهم القيود.

يرجى تصحيحي إذا لزم الأمر.

@david، ألا يمكن لـ Discourse ببساطة أن يقوم الخادم بتوقيع سر الجلسة باستخدام HMAC، ويمكن استخدام سر الجلسة هذا بدوره لتوقيع الأشياء في الجلسة المعطاة؟ إذا تمت سرقته، فمن المحتمل ألا يتم سرقة ملف تعريف ارتباط الجلسة أو CSRF nonce أيضًا. إنه يشبه إلى حد ما سلسلة الشهادات - لا يتعين عليك وضع المفتاح الجذر في المتصفح.

هذه لواجهة برمجة تطبيقات المسؤول فقط. الطريقة التي فهمتها هي أنه بالنسبة لعملاء JavaScript، تحتاج إلى، كما ذكر أعلاه، التحقق من User API keys specification .