ಒಬ್ಬ ಬಳಕೆದಾರರು ತೆರೆದ ಐದು ಟ್ಯಾಬ್ಗಳು ಒಂದೇ ಮಿಲಿಸೆಂಡ್ನಲ್ಲಿ ಅವಧಿ ಮುಗಿದ JWT ಅನ್ನು ರಿಫ್ರೆಶ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ಬ್ಯಾಕ್ಎಂಡ್ಗೆ ಒಂದೇ ರೀತಿಯ ರಿಫ್ರೆಶ್ ವಿನಂತಿಗಳ ಸುರಿಮಳೆಯಾಗಿ ಮತ್ತು ಸೆಷನ್ ಅನ್ನು ತಕ್ಷಣವೇ ಅಮಾನ್ಯಗೊಳಿಸುವ ಮೂಲಕ 'ಟೋಕನ್ ಟ್ರ್ಯಾಪ್' (token trap) ಒಂದು ಲೈವ್ ಸೈಟ್ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರಿತು. ಪ್ರತಿಯೊಂದು ಟ್ಯಾಬ್ ಬಳಕೆದಾರರನ್ನು ಲಾಗ್ ಔಟ್ ಮಾಡಿತು, ಇದು ಟೋಕನ್ ನವೀಕರಣಕ್ಕಾಗಿ ಕೇವಲ ಒಂದೇ ಟ್ಯಾಬ್ನಲ್ಲಿ ಕೆಲಸ ಮಾಡುವ ಪರಿಹಾರವು ಇನ್ನು ಮುಂದೆ ಸಾಕಾಗುವುದಿಲ್ಲ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಿತು.
ಟೋಕನ್ ಟ್ರ್ಯಾಪ್ ಏಕೆ ಮುಖ್ಯ?
ಆಧುನಿಕ ಸಿಂಗಲ್-ಪೇಜ್ ಆಪ್ಗಳು (single-page apps) ಅಲ್ಪಾವಧಿಯ access tokens ಮತ್ತು ದೀರ್ಘಾವಧಿಯ refresh token ಅನ್ನು ಬಳಸುತ್ತವೆ. Access token ಅವಧಿ ಮುಗಿದಾಗ, ಕ್ಲೈಂಟ್ ಒಂದು ರಿಫ್ರೆಶ್ ವಿನಂತಿಯನ್ನು ಕಳುಹಿಸುತ್ತದೆ, ಹೊಸ ಟೋಕನ್ ಜೋಡಿಯನ್ನು ಪಡೆಯುತ್ತದೆ ಮತ್ತು ಮೂಲ ಕರೆಯನ್ನು (original call) ಮರುಪ್ರಯತ್ನಿಸುತ್ತದೆ. ಹೆಚ್ಚಿನ ಅಭಿವೃದ್ಧಿಪಡಿಸುವವರು (developers) ಈ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಇನ್-ಮೆಮರಿ ಫ್ಲಾಗ್ (ಉದಾಹರಣೆಗೆ, isRefreshing = true) ಅಥವಾ ರಿಕ್ವೆಸ್ಟ್ ಕ್ಯೂ (request queue) ಮೂಲಕ ರಕ್ಷಿಸುತ್ತಾರೆ ಮತ್ತು ಇದನ್ನು ಒಂದೇ ಟ್ಯಾಬ್ನಲ್ಲಿ ಪರೀಕ್ಷಿಸುತ್ತಾರೆ. ಆದರೆ ವಾಸ್ತವ ಜಗತ್ತಿನಲ್ಲಿ ಬಳಕೆದಾರರು ಹಲವಾರು ಟ್ಯಾಬ್ಗಳನ್ನು ತೆರೆದಿಡುತ್ತಾರೆ: ಸೆಟ್ಟಿಂಗ್ಸ್ ಪೇಜ್, ಅನಾಲಿಟಿಕ್ಸ್ ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಮತ್ತು ಕೆಲವು ಡೇಟಾ ವ್ಯೂಗಳು. Access token ಅವಧಿ ಮುಗಿದಾಗ, ಪ್ರತಿಯೊಂದು ಟ್ಯಾಬ್ ಸ್ವತಂತ್ರವಾಗಿ 401 ಎರರ್ ಅನ್ನು ಪತ್ತೆಹಚ್ಚುತ್ತದೆ, ಪ್ರತಿಯೊಂದೂ ರಿಫ್ರೆಶ್ ವಿನಂತಿಯನ್ನು ಕಳುಹಿಸುತ್ತದೆ ಮತ್ತು ಬ್ಯಾಕ್ಎಂಡ್—ವಿಶೇಷವಾಗಿ ಅದು refresh-token rotation ಅನ್ನು ಜಾರಿಗೊಳಿಸಿದಾಗ—ಎರಡನೇ ವಿನಂತಿಯನ್ನು 'ರೀಪ್ಲೇ' (replay) ಎಂದು ಪರಿಗಣಿಸಿ ಇಡೀ ಸೆಷನ್ ಅನ್ನು ರದ್ದುಗೊಳಿಸುತ್ತದೆ.
JavaScript ಐಸೊಲೇಶನ್ (isolation) ಸಮಸ್ಯೆಯನ್ನು ಸೃಷ್ಟಿಸುತ್ತದೆ
ಪ್ರತಿಯೊಂದು ಬ್ರೌಸರ್ ಟ್ಯಾಬ್ ತನ್ನದೇ ಆದ JavaScript context ಅನ್ನು ಚಲಾಯಿಸುತ್ತದೆ. ಒಂದೇ ಮೂಲವನ್ನು (origin) ಹಂಚಿಕೊಂಡಿದ್ದರೂ ಸಹ, ವೇರಿಯೇಬಲ್ಗಳು, ಟೈಮರ್ಗಳು ಮತ್ತು ಇನ್-ಮೆಮರಿ ಫ್ಲಾಗ್ಗಳು ಇತರ ಟ್ಯಾಬ್ಗಳಿಗೆ ಕಾಣಿಸುವುದಿಲ್ಲ. "ರಿಫ್ರೆಶ್ ಪ್ರಕ್ರಿಯೆ ಈಗಾಗಲೇ ನಡೆಯುತ್ತಿದೆ" ಎಂದು ಹೇಳುವ ಫ್ಲಾಗ್ ಅದನ್ನು ಸೆಟ್ ಮಾಡಿದ ಟ್ಯಾಬ್ನೊಳಗೆ ಮಾತ್ರ ಇರುತ್ತದೆ. ಟೋಕನ್ ಅನ್ನು ಬೇರೆಡೆ ರಿಫ್ರೆಶ್ ಮಾಡಲಾಗುತ್ತಿದೆ ಎಂದು ತಿಳಿಯಲು ಇತರ ಟ್ಯಾಬ್ಗಳಿಗೆ ಯಾವುದೇ ಮಾರ್ಗವಿಲ್ಲ, ಆದ್ದರಿಂದ ಅವುಗಳೆಲ್ಲವೂ ತಮ್ಮದೇ ಆದ ನೆಟ್ವರ್ಕ್ ಕರೆಯನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತವೆ. ಈ ಸಮಸ್ಯೆ ಇಂಟರ್ಸೆಪ್ಟರ್ನಲ್ಲಿರುವ (interceptor) ಬಗ್ ಅಲ್ಲ; ಇದು ಕ್ಲೈಂಟ್-ಸೈಡ್ ಸ್ಟೇಟ್ ಐಸೊಲೇಶನ್ನ (client-side state isolation) ಮೂಲಭೂತ ಮಿತಿ.
Web Locks API ಪರಿಹಾರ ನೀಡುತ್ತದೆ
ಒಂದು ಟ್ಯಾಬ್ ಲಾಕ್ (lock) ಅನ್ನು ಹಿಡಿದholdingಾಗ, ಅದೇ ಲಾಕ್ ಅನ್ನು ಕೇಳುವ ಯಾವುದೇ ಇತರ ಟ್ಯಾಬ್ ಅದನ್ನು ಬಿಡುವವರೆಗೆ ಕಾಯಲೇಬೇಕು.
ಟೋಕನ್ ರಿಫ್ರೆಶ್ಗಾಗಿ ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ
- 401 ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿ – ಅನಧಿಕೃತ ಪ್ರತಿಕ್ರಿಯೆಯನ್ನು (unauthorized response) ಪಡೆಯುವ ಯಾವುದೇ ಟ್ಯಾಬ್
navigator.locks.request('auth_token_refresh_lock', async lock => { … })ಅನ್ನು ಕರೆಯುತ್ತದೆ. - ಲಾಕ್ ಪಡೆಯಿರಿ – ಬೇರೆ ಯಾವುದೇ ಟ್ಯಾಬ್ ಲಾಕ್ ಅನ್ನು ಹಿಡಿದholdingಿಲ್ಲದಿದ್ದರೆ, ಪ್ರಸ್ತುತ ಟ್ಯಾಬ್ ಮುಂದುವರಿಯುತ್ತದೆ; ಇಲ್ಲದಿದ್ದರೆ ಲಾಕ್ ಬಿಡುವವರೆಗೆ ಅದು ನಿಲ್ಲುತ್ತದೆ.
- ಒಮ್ಮೆ ರಿಫ್ರೆಶ್ ಮಾಡಿ – ಲಾಕ್ ಹೊಂದಿರುವ ಟ್ಯಾಬ್ ರಿಫ್ರೆಶ್ ವಿನಂತಿಯನ್ನು ಕಳುಹಿಸುತ್ತದೆ, ಹೊಸ access token ಮತ್ತು ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ ಅನ್ನು
localStorageನಲ್ಲಿ ಸಂಗ್ರಹಿಸುತ್ತದೆ, ಮತ್ತು ನಂತರ ಕಾಲ್ಬ್ಯಾಕ್ ಮುಗಿದಾಗ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಲಾಕ್ ಅನ್ನು ಬಿಡುತ್ತದೆ. - ನಕಲಿ ಕೆಲಸವನ್ನು ಬಿಟ್ಟುಬಿಡಿ – ಕಾಯುತ್ತಿರುವ ಟ್ಯಾಬ್ ಅಂತಿಮವಾಗಿ ಲಾಕ್ ಪಡೆದಾಗ, ಅದು
localStorageನಿಂದ ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ ಅನ್ನು ಓದುತ್ತದೆ. ಟೋಕನ್ ಅನ್ನು ನಿರ್ದಿಷ್ಟ ಅವಧಿಯೊಳಗೆ (ಉದಾಹರಣೆಗೆ, ಕಳೆದ ಕೆಲವು ಸೆಕೆಂಡುಗಳು) ರಿಫ್ರೆಶ್ ಮಾಡಿದ್ದರೆ, ಆ ಟ್ಯಾಬ್ ನೆಟ್ವರ್ಕ್ ಕರೆಯನ್ನು ಬಿಟ್ಟುlocalStorageನಿಂದ ತನ್ನ ಇನ್-ಮೆಮರಿ ಟೋಕನ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡುತ್ತದೆ. - ಕ್ರ್ಯಾಶ್ಗಳನ್ನು ನಿರ್ವಹಿಸಿ – ಲಾಕ್ ಹಿಡಿದಿರುವಾಗ ಒಂದು ಟ್ಯಾಬ್ ಕ್ರ್ಯಾಶ್ ಆದಾಗ ಅಥವಾ ಮುಚ್ಚಲ್ಪಟ್ಟಾಗ, ಬ್ರೌಸರ್ ಲಾಕ್ ಅನ್ನು ಬಿಡುತ್ತದೆ, ಇದು ಮತ್ತೊಂದು ಟ್ಯಾಬ್ ರಿಫ್ರೆಶ್ ಅನ್ನು ಮರುಪ್ರಯತ್ನಿಸಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ.
ಪ್ರಯೋಜನಗಳು ಒಮ್ಮೆ ನೋಟದಲ್ಲಿ
- ಶೂನ್ಯ ಅನಗತ್ಯ ನೆಟ್ವರ್ಕ್ ಕರಗಳು – ಮೊದಲ ಟ್ಯಾಬ್ ಮಾತ್ರ ಬ್ಯಾಕ್ಎಂಡ್ಗೆ ಸಂವಹನ ನಡೆಸುತ್ತದೆ.
- ಸೆಷನ್ ನಾಶವಾಗುವುದಿಲ್ಲ – ರಿಫ್ರೆಶ್-ಟೋಕನ್ ರೊಟೇಶನ್ ಒಂದೇ ಬಳಕೆಯನ್ನು ನೋಡುತ್ತದೆ, ಇದರಿಂದ ಸೆಷನ್ ಜೀವಂತವಾಗಿರುತ್ತದೆ.
- ಸುಗಮ ಚೇತರಿಕೆ (Graceful recovery) – ಟ್ಯಾಬ್ ಮಾಯವಾದರೆ ಬ್ರೌಸರ್ ನಿರ್ವಹಿಸುವ ಲಾಕ್ ಬಿಡುಗಡೆಯು ডেಡ್ಲಾಕ್ಗಳನ್ನು (deadlocks) ತಡೆಯುತ್ತದೆ.
ಅಳವಡಿಕೆಯ ಪರಿಶೀಲನಾ ಪಟ್ಟಿ (Implementation checklist)
- ನಿಮ್ಮ Axios (ಅಥವಾ fetch) ಇಂಟರ್ಸೆಪ್ಟರ್ನಲ್ಲಿ ಲಾಕ್ ವಿನಂತಿಯೊಂದಿಗೆ ರಿಫ್ರೆಶ್ ಲಾಜಿಕ್ ಅನ್ನು ಸುತ್ತುವರಿಯಿರಿ (wrap).
- ರಿಫ್ರೆಶ್ ಮಾಡಿದ ಟೋಕನ್ ಮತ್ತು ಮಿಲಿಸೆಕೆಂಡ್ ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್
