Keycloakify'ning page_hint holat boshqaruvi yaxshilanishi

Keycloakify'ning page_hint holat boshqaruvi yaxshilanishi

Kirish

Hozirgi loyihada Keycloak asosidagi kirish va hisob bilan bog'liq sahnalarni qo'llab-quvvatlayapman. Bu safar xodim hisobining dastlabki sozlash sahnasida yangilanish paytida oddiy parolni tiklash sahnasiga o'tadigan muammoni aniqladim va sabablarini tahlil qildim.

Birinchida, oddiy React SPA kabi o'yladim, ekranni ajratish uchun qiymatni URL so'rov parametrlari orqali kiritish kifoya deb o'yladim. Ammo kodni kuzatganda, Keycloakify ushbu usul bilan yetarli emas ekanligini ko'rdim. Sabab Keycloakify'ning ekran almashuvi usuli va Keycloak'ning aylanish jarayonida edi.

URL barchasi bo'lishi uchun yetarli emasdi

Masalani ko'rganimda, oddiy yondashdim. Xodim hisobining dastlabki sozlash sahnasi va oddiy parolni tiklash sahnasini ajratish kerak, shuning uchun URL'ga page_hint=isTemp kabi qiymat qo'shish va bu qiymat asosida ekranlarni bo'lish kerak deb o'yladim.

Oddiy React SPA bo'lsa, bu usul juda g'alati emas. Ekran almashinuvi odatda react-router orqali boshqariladi va URL yo'li yoki so'rov parametrlari o'zgarganda shunga mos komponentlarni tasvirlaydi. Ekran holati ham ko'pincha React holati yoki so'rov parametrlari orqali boshqariladi. Ammo Keycloakify sahnalari biroz boshqacha ishlaydi. Keycloak kirish, parolni tiklash, parolni o'zgartirish kabi sahnalarni pageId bo'yicha berib turadi.

login.ftl
login-reset-password.ftl
login-update-password.ftl

Keycloakify ushbu pageId ga mos React komponentini tasvirlaydi. Ya'ni ekran React bilan yaratiladi, lekin umumiy oqim Keycloak'ning autentifikatsiya oqimida harakat qiladi. Masalan, parolni tiklash sahnasiga o'tganingizda, oddiygina React ichki routeri bilan o'tish emas, Keycloak tomonidan taqdim etilgan URL orqali butun sahna harakatda bo'ladi.

const findPassword = useCallback(() => {
  if (!("loginResetCredentialsUrl" in kcContext.url)) return;
  window.location.href = kcContext.url.loginResetCredentialsUrl;
}, [kcContext.url]);

Ushbu usulda ekran o'zgarganda sahna butunlay qayta yuklanadi, shuning uchun faqat React holatida saqlangan qiymatlar saqlanmaydi. Oddiy SPA'da tabiiy ravishda saqlanib qolishi kerak bo'lgan holatlar, Keycloakify sahna o'tish jarayonida yo'q bo'lib ketishi mumkin.

Keycloak aylanishi va holat yo'qolishi

Shunday qilib, URL so'roviga qiymat kiritish mumkin, lekin Keycloakify'da bu ham yetarli emas. Nima uchun ekanligini tushunish uchun avvalo "aylanish" nima ekanligini belgilashimiz kerak.

Bu yerda aytilayotgan aylanish, so'rovning brauzerdan chiqib, Keycloak serveriga yetib borishi va yangi sahna bo'lib qaytishi deganidir. Oddiy SPA'da ekran o'zgarsa, brauzer hamon bir xil sahnada qoladi va JavaScript faqat ekranni almashtiradi. Biroq, Keycloak autentifikatsiya oqimi bunday emas. Kirish yoki parolni tiklash kabi oqimlarda front to'g'ridan-to'g'ri API'ni chaqirmaydi, Keycloak tomonidan berilgan harakat URL'siga forma POST qiladi.

<form method="post" action={kcContext.url.loginAction}>

Ushbu forma yuborilgach, oqim taxminan quyidagi kabi davom etadi.

  1. Brauzer hozirgi React ekranidan chiqib, Keycloak serveriga POST so'rovini yuboradi.

  2. Keycloak serverda autentifikatsiya oqimini hal qiladi.

  3. Hisobga olish natijalariga mos keladigan keyingi sahna (keyingi pageId) server tomonidan yangi yaratiladi.

  4. Brauzer ushbu javobni qabul qiladi va sahnani boshidan qayta render qiladi.

Ya'ni, ekran almashtirishni nazorat qilish Reactga emas, balki Keycloak serveriga tegishli, va jarayonda sahna butunlay qayta chiziladi. Bu bir aylana chaqiriqdir.

Muammo shundaki, ushbu vaqtda brauzer URLi Keycloak tomonidan yana qayta yaratiladi. Shuning uchun avvalgi ekrandagi ?page_hint=isTemp kabi query parametrlari keyingi ekranga saqlanib qolishiga ishonch hosil qilib bo'lmaydi. Aksincha, React holati sahna qayta yuklanganda albatta yo'qoladi. Shuning uchun ushbu loyihada page_hintni URL va sessionStorageda boshqarayotgan edik.

let page = params.get("page_hint") || sessionStorage.getItem("page_hint");

Bir xil qiymatni ikkita joydan o'qish sababi aylana chaqiriqni hisobga olganda aniq bo'ladi.

  • URL query hozirgi ekran holatini ko'rsatish uchun yaxshi, lekin aylana chaqiriq paytida yo'qolishi mumkin.

  • sessionStorage yangilanish va aylana chaqiriqdan keyin qoladi, lekin juda uzoq qolsa, boshqa oqimga ta'sir qiladi.

Ya'ni, URL ham yetarli emas va sessionStorage ham xavflidir. Shuning uchun sessionStoragega qiymat zaxiralab qo'yildi va renderlashda yana URLga aks ettirish tuzilmasi mavjud edi.

function syncPageHintToUrl(pageHint: string) {
  const url = new URL(window.location.href);
  url.searchParams.set(&quot;page_hint&quot;, pageHint);
  window.history.replaceState(null, &quot;&quot;, url.toString());
}

page_hint orqali batafsil ekranlarni ajratish usuli

Amaldagi xizmatda Keycloakning pageId biri ichida page_hintdan foydalanib bir nechta ekranlarni ko'rsatish kerak bo'ldi. Parolni resetting ekranini ham oddiy parolni topish ekrani va xodimlar hisobini birinchi marta sozlash ekrani bilan ajratish zarur edi. Xodimlar hisobini birinchi marta sozlashga kirganda, page_hintni isTemp qilib quyidagi kabi saqlab, parolni qidirish jarayoniga o'tishdi.

onClick={() =&gt; {
  sessionStorage.setItem(&quot;page_hint&quot;, &quot;isTemp&quot;);
  links.findPassword();
}}

Kelgan konteyner ushbu qiymatga asoslanib qanday ekran ko'rsatishni belgilaydi.

return isTemp
? <ResetVerifyStaff kcContext={kcContext} />
: <FindPassword kcContext={kcContext} />;

Yangilash paytida ekran o'zgarishining sababi

Muammo xodimlar hisobini birinchi marta sozlash ekranida yangilash amalga oshirganda yuzaga keldi. Dastlab kirilganda xodimlar ekrani normal ko'rinardi, lekin yangilashdan so'ng oddiy parolni topish ekraniga o'zgarib ketdi. Sabablarga qaraganda, bir xil konteyner ichida quyidagi kod bor edi.

useEffect(() =&gt; {
  sessionStorage.removeItem(&quot;page_hint&quot;);
  const url = new URL(window.location.href);
  url.searchParams.delete(&quot;page_hint&quot;);
  window.history.replaceState(null, &quot;&quot;, url.toString());
}, []);

Konteyner o'rnatilgunga qadar xodimlar ekranini ajratuvchi page_hintni sessionStorage va URLdan hamma joydan o'chirganligi sababli yangilash paytida xodimlar ekranini aniqlab bo'lmadi.

O'chirish kodining sababini tekshirish

Bevosita olib tashlamoqchi bo'lganimda, autentifikatsiya va hisob ekranlari bir nechta oqimlar bilan bog'liq bo'lganligi sababli, avval qo'shish tarixini tekshirishga to'g'ri keldi. Ushbu o'chirish kodi Mening sahifam parolni o'zgartirish ekranining xatolarini oldini olish uchun himoya kodidir. page_hint=isTemp sessionStorageda qolganida, keyinchalik boshqa yo'l bilan parol o'zgartirish ekraniga kirganda ham xodimlar ekranini noto'g'ri aniqlash mumkin edi, shuning uchun kirganda o'chirib qo'yilgan edi.

Muammo mohiyati shu yerda namoyon bo'ldi. page_hint=isTemp ikkita vazifani bir vaqtning o'zida bajarayotgan edi.

  • Xodimlar hisobini dastlabki sozlash jarayonini saqlab qolish uchun qiymat

  • Boshqa oddiy jarayonda qolmasligi kerak bo'lgan qiymat

Bir tomondan saqlanib, boshqa tomondan o'chirilishi kerak bo'lgani uchun, shunchaki “o'chirish logikasini olib tashlash” boshqa jarayonlarga ta'sir ko'rsatishi mumkin edi.

Tahlil yo'nalishi

Qayta kirish yo'lini tekshirganda, parolni qayta tiklash ekraniga kiradigan asosiy kirish nuqtasida allaqachon page_hintni aniq belgilab qo'yilgan edi.

// 일반 비밀번호 찾기
onClick={() =&gt; {
  sessionStorage.setItem(&quot;page_hint&quot;, &quot;&quot;);
  links.findPassword();
}}
// 직원 계정 최초 설정
onClick={() =&gt; {
  sessionStorage.setItem(&quot;page_hint&quot;, &quot;isTemp&quot;);
  links.findPassword();
}}

Ya'ni, LoginResetPasswordContainer'da kirish nuqtasida allaqachon jarayon belgilangan edi, lekin kelgandan so'ng har doim page_hintni o'chirgan holda, yangilanishda ekran holati saqlanmayapti. LoginUpdatePasswordContainer esa Mening sahifamdagi parol o'zgartirish jarayoni bilan bog'langan, shuning uchun eski himoya logikasi hali ham zarur edi. Boshqa tomondan, LoginResetPasswordContainer kirish nuqtasida allaqachon page_hintni aniq belgilab qo'yganligi sababli, kelgandan so'ng har doim o'chirish zarur emas deb qaror qildim va quyidagicha o'zgartirdim.

  • LoginResetPasswordContainer'ning montajida page_hintni o'chirish logikasini olib tashlash

  • LoginUpdatePasswordContainer'ning o'chirish logikasini saqlash

Bir necha o'zgartirishlar qilingan bo'lsa-da, xavfsiz o'chirib qo'yish uchun Keycloakify'ning yo'nalish tuzilishi, round trip jarayoni, eski himoya kodining sabablari bilan birga ko'rib chiqilishi kerak edi.

Tahlil

Bu muammo, ekran ajratish qiymati bo'lgan page_hint montajdan so'ng bekor qilinganligi sababli, yangilanishda xodim ekranini aniqlay olmasligi sabab bo'ldi. Ish orqali Keycloakify asosida sahna, oddiy React SPA'dan farqli o'laroq holatni boshqarish kerakligini tushundik. Keycloak sahna almashinishni boshqaradi va forma POST'dan keyin server orqali sahna qaytadan tushadi, shuning uchun URL so'rov yoki React holati bilan sahna holatini barqaror saqlash qiyin.

Shuningdek, sessionStorage kabi uzoq vaqt qoladigan saqlash joylarini ishlatganingizda, boshqa jarayonlarga holatning tushishiga yo'l qo'ymaslik kerak. Bu kabi bir page_hint qiymati “sahna saqlash” va “jarayon ajratish” vazifasini bir vaqtning o'zida bajarganda, ma'lum bir vaqtga saqlanishi va ma'lum bir vaqtga o'chirilishi kerak bo'lgan to'qnashuvlar paydo bo'lishi mumkin.

Natijada, ushbu o'zgartirish bir necha qatorlarni olib tashlashni o'z ichiga olsa-da, bu qatorlarni xavfsiz o'chirish uchun Keycloakify'ning yo'nalish tuzilishi va eski holatni boshqarish maqsadini avval tushunish zarur edi.

Lynn

Site footer