اذهب إلى المحتوى
  • 0

مشكلة CORS بين لارافيل و Angular

Amir Alsaeed

السؤال

لدي تطبيق Angular يعمل بالتوازي مع Laravel من جهة الخادم، ولكن كل منهما على خادم ويب منفصل وخادم الويب الذي يحوي Angular يقوم بتزويد الواجهات الرسومية إلى تطبيقات Cordova. ولكن أواجه مشكلة CORS عند طلب البيانات من الخادم، حتى مع محاولتي لمعالجتها بقي الخطأ كما هو.

وعند طلب البيانات أحصل على الخطأ التالي في console:

No 'Access-Control-Allow-Origin' header is present on the requested resource

ولكن عند تجربتي للطلب GET التالي يعمل ولا يظهر أي خطأ:

Route::get('example', ['middleware' => 'cors', function(){
    return Response::json(array('name' => 'Steve Jobs 1', 'company' => 'Apple'));
}]);

ولكن المسارات التالية التي تحتاج التحقق token-based هي التي تظهر الخطأ فقط:

Route::group(['middleware' => 'cors'], function () {
Route::group(['prefix' => 'api'], function()
{
    Route::resources('authenticate', 'AuthenticateController', ['only' => ['index']]);
    Route::post('authenticate', 'AuthenticateController@authenticate');
});
});

وهذه هي إعدادات ال cors الخاصة بالتطبيق:

class CORS
{
/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    header("Access-Control-Allow-Origin: *");

    
    $headers = [
        'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
        'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin'
    ];
    if($request->getMethod() == "OPTIONS") {
        // The client-side application can set only headers allowed in Access-Control-Allow-Headers
        return Response::make('OK', 200, $headers);
    }

    $response = $next($request);
    foreach($headers as $key => $value)
        $response->header($key, $value);
    return $response;
    return $next($request);
}
}

فكيف يمكنني حل هذه المشكلة مع استخدام tokens مع خادم الويب الذي بضمنه Angular؟

رابط هذا التعليق
شارك على الشبكات الإجتماعية

Recommended Posts

  • 0

إن السبب في ذلك هو أن middlewares في لارافيل والموجودة ضمن مصفوفة $routeMiddleware يتم تطبيقها والتحقق منها مباشرةً بعد تأكد لارافيل من المسار المزود عن طريق HTTP والسبب في ذلك لأن مسارات الطلبات المختلفة قد يكون لها middlewares مختلفة أيضاً.

لأنه عندما يتم إرسال الطلبات POST, PUT, DELETE وغيرها... سيتم إرسالها إلى /api/authenticate والمتصفح يقوم بإرسال Options أولاً وبالتالي لارافيل يقوم بتسجيل المسار والتحقق من تطابقه مع المسارات الموجودة قبل الدخول والتحقق في middlewares  وبما أن الموارد resources لا تحوي Options أو دوال معينة للتعامل معها لن تقوم بالتالي بالتحقق من أي middleware مرفق مع المسار وهنا يحدث الخطأ. مثال:

Route::group(['middleware' => 'cors'], function () {
  Route::group(['prefix' => 'api'], function() {
     Route::resources('authenticate', 'AuthenticateController', ['only' => ['index']]);
     Route::post('authenticate', 'AuthenticateController@authenticate');
  });
});

أما middlewares الموجودة ضمن مصفوفة $middleware يتم التحقق منها وتطبيقها (قبل) أن يقوم لارافيل بتسجيل المسار والتحقق من وجوده.

فعملية المطابقة matching تستدعي findRoute الموجود ضمن:

vendor/laravel/framework/src/Illuminate/Routing/Router.php

على الشكل التالي:

/**
 * Find the route matching a given request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Routing\Route
 */
protected function findRoute($request)
{
    $this->current = $route = $this->routes->match($request);

    $this->container->instance(Route::class, $route);

    return $route;
}

لذلك لحل هذه المشكلة، يجب استخدام middleware عام أي (global) والذي بدوره يستقبل الخيارات الموجودة ضمن الترويسة OPTIONS ولاختصار الوقت والجهد يمكن استعمال مكتبة fruitcake / laravel-cors الموجودة والتي يمكن إضافتها إلى لارافيل والتي ستقوم بدورها باستعمال CORS الخاصة بها مثل أن يكون cors خاصة لكل مسار أو مجموعة أو لاحقة prefix في ملف api.php وتقوم بحل المشكلة الموجودة.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

توجد طريقة أخرى لتفادي هذا المشكل و هي :

1- أنشئ middleware بسيطة وسمها مثلا Cors:

php artisan make:middleware Cors

2- أضف التعليمات البرمجية التالية إلى app/Http/Middleware/Cors.php

public function handle($request, Closure $next)
{
    return $next($request)
        // هنا أضع الإستضافات المسموح بها , في هذه الحالة مسموح لجميع الإستضافات
        ->header('Access-Control-Allow-Origin', '*')
       // هنا يمكنك إضافة الدوال المسموح بها 
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
}

  يمكنك استبدال * ب localhost إدا كنت في المضيف المحلي


 3-تحميل البرمجيات الوسيطة. أضف السطر التالي إلى مصفوفة  routeMiddleware$  في app/Http/Kernel.php

'cors' => \App\Http\Middleware\Cors::class, 

4- والخطوة الأخيرة هي استخدام Middleware على المسارات التي تريدها : 

بافتراض أنك تتحدث عن مسارات api جديدة في Laravel  ، فإن المكان المناسب للقيام بذلك هو app/Providers/RouteServiceProvider.php ، داخل وظيفة mapApiRoutes 

  Route::group([
        'middleware' => ['api', 'cors'],
        'namespace' => $this->namespace,
        'prefix' => 'api',
    ], function ($router) {
         // يمكن إضافةالمسرات الخاصة بك هنا
         Route::apiResource('/posts','PostController');
    });

بعد ذلك لن يظهر لك هذا المشكل بعد إضافة cors  middleware في RouteServiceProvider.php

تم التعديل في بواسطة محمد أيت لعرايك
رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

الجواب البسيط هو أنك تحتاج إلى اعتراض طلباتك (request interception) باستخدام برمجية وسيطة (middleware) وتعيين الـ CORS بشكل صحيح. ولكن دعني أشرح لك ما هو CORS و Access-Control-Allow-Origin.

لأسباب تتعلق بالسلامة، يجب تشغيل تطبيقات الويب في بيئات منعزلة، ما لم ينص على خلاف ذلك. ببساطة، يجب بدء الاتصال بطلب (request)، وسيحتاج هذا الطلب في النهاية إلى استجابة (response). هذه هي الطريقة التي يعمل بها الاتصال في HTTP (المتصفحات). تتم هذه الاتصالات لمشاركة الموارد (على سبيل المثال، ملف JavaScript أو استجابات HTML أو JSON).

مثال بسيط:

  • يريد المستخدم تحميل شيء ما على origin A، والذي يتطلب الوصول إلى البيانات من origin B.
  • يعالج الخادم الطلب ويرسل بعض العناوين (headers) (بما في ذلك Access-Control-Allow-Origin التي تحتوي على المواقع آمنة).
  • يحصل المتصفح على الاستجابة ويقرر ما إذا كان سيمنح المستخدم حق الوصول إلى البيانات أم لا.

فمثلاً، إذا كانت لديك endpoint على الخادم الخاص بك، وتريد أن يصل الجميع إليها، فسيتعين عليك تعيين Access-Control-Allow-Origin للقيمة "*".

مثال من العالم الحقيقي، إذا كنا نكتب بيانات حساسة لمعالجة تطبيق (على سبيل المثال، تطبيق مصرفي) وأردنا تقديم الـ Front-End والـ Back-End من نقاط نهاية مختلفة (endpoints) وأردنا السماح للـ Front-End فقط بقراءة البيانات، فسيتعين علينا إدراجها في القائمة البيضاء عن طريق Access-Control-Allow-Origin.

لذلك، إذا كان الـ Front-End عرضة للهجمات، فسيكون من المستحيل على شخص ما قراءة البيانات من الـ Back-End وتمريرها إلى خادم آخر.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...