Relogin و HTTP Basic Auth

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

سأحجز على الفور أنني لست مطورًا أماميًا ، ولم أذهب إلى مجموعة كاملة من "العلامات التجارية" وإصدارات المتصفح. فقط مع الإصدارات ذات الصلة في وقت كتابة هذا التقرير. بالنسبة لمعظم مهام الويب ، هذا يكفي. بالنسبة للمطورين الذين يحتاجون إلى دعم "حديقة الحيوانات" بأكملها ، يمكن أن تكون المقالة نقطة بداية جيدة.

جوهر المشكلة هو أن معيار مصادقة HTTP الأساسي لا يوفر التسجيل. عموما. عندما تنتقل إلى صفحة محمية بواسطة التفويض الأساسي ، يعرض المستعرض نفسه نافذته الخاصة مع طلب تسجيل الدخول / كلمة المرور ، ومع تسجيل الدخول الناجح ، يحفظها في مكان ما في أعماقها. بعد ذلك ، ستستخدم جميع الطلبات اللاحقة للصفحات المحمية الأخرى من هذا الموقع تلقائيًا هذه القيم في رأس التفويض:
التفويض: Basic bm9uZTpub25l
حيث bm9uZTpub25l هو ارتباط تسجيل الدخول / كلمة المرور المشفرة باستخدام base64 بلا: لا شيء (قد يكون اسم المستخدم وكلمة المرور مختلفين)

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

الأسوأ من ذلك ، نظرًا لأن نافذة طلب تسجيل الدخول / كلمة المرور هي نافذة المتصفح الخاصة بها ، والتي تستجيب بالفعل لرؤوس صفحات HTTP فقط ، تنبثق هذه النافذة قبل أي معالجة لنص الصفحة. وهذا يعني ، لتنفيذ بعض جافا سكريبت عند لا يعمل استجابة خادم مع حالة 401. أمام المستخدم ، ستظهر هذه النافذة مرارًا وتكرارًا مع طلب متكرر لتسجيل الدخول / كلمة المرور.

في الواقع ، هذه النقطة حاسمة ، نظرًا لأن جميع المتصفحات تقريبًا ، فإن الطريقة الوحيدة لتسجيل الخروج هي إرسال طلب إلى الخادم باستخدام اسم مستخدم / كلمة مرور خاطئ بشكل واضح ، وتلقي استجابة الخادم بالحالة 401 ثم إعادة تعيين ذاكرة التخزين المؤقت لتسجيل الدخول / كلمة المرور للمتصفح. ولكن إذا لم يسمح لك المتصفح في نفس الوقت بمعالجة الاستجابة 401 ومواصلة عملية تسجيل الدخول بالفعل للمستخدم الجديد ، فإن التحكم حتى في مرحلة قراءة رؤوس HTTP وإلقاء شكل التفويض الذي تدخله فيه لن يعمل في وجهك ، فإن هذا مشكلة بالفعل. لا يهم إذا كان هذا طلبًا عاديًا حسب المرجع أو XMLHttpRequest أو الجلب. لا يزال المتصفح يتحكم في مرحلة تحليل الرؤوس.

وبالتالي…

البيانات الأولية:


  1. هناك صفحة منفصلة logout.html يوجد فيها كل المنطق في نص جافا سكريبت ، يتم إعطاء أجزاء منه أثناء العرض التقديمي
  2. عنوان Url المحدد - عنوان الصفحة لإعادة التوجيه بعد تسجيل الدخول بنجاح
  3. تم تحديد Url401 - عنوان الصفحة الذي يعرض دائمًا خطأ HTTP 401 (غير مصرح به)

// file logout.html
const url = new URL("http://mysite.com/");
const url401 = new URL("http://mysite.com/401");

متصفح الانترنت


لا يتطلب منتجنا دعمًا لهذا المتصفح ، لذلك فإن الحل الذي لم أختبره شخصيًا. ومع ذلك ، وفقًا لـ Google ، هناك حل لها ، وربما يكون هو الأبسط والأكثر أناقة على الإطلاق. علاوة على ذلك ، لم أقابل مطلقًا أي معلومات يفقد هذا الحل لمتصفحات Microsoft أهميته:

if (document.execCommand("ClearAuthenticationCache")) {
    window.location.assign(url);
}

في IE ، هناك طريقة ClearAuthenticationCache تتجاهل "تلك الأمعاء العميقة جدًا". بسيط وأنيق. ولا رقص مع الصفحة الإضافية 401. لا أعرف ما إذا كانت هذه الطريقة تعمل في Edge. ربما نعم.

ترجع بنية document.execCommand القيمة true إذا كانت الطريقة موجودة و "نجحت". ثم يعيد window.location.assign (url) توجيه المستخدم لإدخال اسم مستخدم وكلمة مرور جديدين

Firefox (72.0.1)


في سياق مهمتنا ، هذا هو المتصفح الأكثر إشكالية. بالنسبة له ، لا يزال الحل الكامل غير موجود. لمدة 15-20 سنة ، تم تعليق طلب للمشكلة المشار إليها في تعقب الأخطاء لفريق مطوريها. لكن "الأمور لا تزال هناك". الحد الأقصى الذي يمكن تحقيقه هو منحنى razlogin.

الإدخال:
لا يقوم Firefox بمسح ذاكرة التخزين المؤقت لكلمة المرور بعد تلقي استجابة 401 من خلال إما XMLHttpRequest أو طلب إحضار. فقط من خلال طلب منتظم مع تسجيل الدخول / كلمة المرور في عنوان URL نفسه. أي شيء من هذا القبيل
http: // none: none@mysite.com/
الرمز:

else if (/firefox|iceweasel|fxios/i.test(window.navigator.userAgent)) {
    url.username = 'none';
    url.password = 'none';
    window.location.assign(url);
}

بعد ذلك يتلقى المستخدم نموذج إدخال تسجيل الدخول / كلمة المرور ، والذي سيظهر فيه كل ما تدخله مرارًا وتكرارًا. والحقيقة هي أن القيم المدخلة لن تتجاوز قيم تسجيل الدخول / كلمة المرور المحددة في عنوان URL. أي ، بدلاً من القيم التي تم إدخالها ، مجموعة من لا شيء: لن يذهب أي منها إلى الخادم في كل مرة. ولتسجيل الدخول باسم مختلف ، يجب على المستخدم النقر فوق "إلغاء الأمر" والانتقال إلى صفحة البدء (http: //mysite.com/) وإدخال تسجيل دخول / كلمة مرور جديدة هناك.

ملتوية؟ ولكن للأسف ، لا يوجد حل آخر

Google Chrome (79.0.3945.88)


بالنسبة إلى Chrome ، تعمل طريقة الجلب بشكل رائع. لكن XMLHttpRequest لا يعمل (((لم يتم مسح ذاكرة التخزين المؤقت ، ولم يتم تسجيل الدخول. علاوة على ذلك ، حاولت تعيين تسجيل الدخول / كلمة المرور كمعلمات للطريقة المفتوحة وتعيين الرأس.

else if (/chrome/i.test(window.navigator.userAgent)) {
    fetch(url401, {
      credentials: 'include',
      headers: {
        'Authorization': 'Basic ' + btoa('none:none'),
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(() => {
      window.location.assign(url);
    }).catch(err => console.error(err));
}

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

مهم! يجب ألا يعرض الخادم رأس مصادقة WWW . خلاف ذلك ، سيتحكم المتصفح ، ولن تحدث عمليات إعادة التوجيه من الصفحة 401 مطلقًا. حسب الاصطلاح ، يجب ألا يعرض الخادم هذا الرأس إذا تم تحديد X-Requested-With: XMLHttpRequest في الطلب . لذلك ، تمت إضافة رأس X-Requested-With إلى الطلب .

سفاري (12)


بالنسبة إلى Safari ، فإن الوضع هو العكس تمامًا: يعمل XMLHttpRequest ، ولكن لا يعمل الجلب

else {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url401, true, 'none', 'none');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onerror = function(err) {
      console.error(err);
    };
    xhr.onload = function () {
      window.location.assign(url);
    };
    xhr.send()
}

الإجراءات هي نفسها الموجودة في Chrome ، فقط من خلال XMLHttpRequest

ينبغي أن تعمل مع إصدارات Safari 6+. الإصدارات السابقة لها أخطاء خاصة بها. على وجه الخصوص ، على سبيل المثال ، في الإصدارات من 5.1 ، مع كل عملية إعادة توجيه ، أعاد المتصفح طلب الإذن بالقوة ، وهذا هو السبب في أن التفويض مع إعادة التوجيه إلى الصفحة الأخيرة لم يعمل من حيث المبدأ. وفي الإصدارات السابقة للإصدار 5.0 ، لم يعمل التسجيل.

All Articles