解決sessionStorage不能跨標籤頁共享

用戶在一個標籤頁已登陸,再打開多個標籤頁,此場景下將token保存在sessionStorage中將會帶來不好的用戶體驗,每次開啓一個標籤頁都會要求用戶從新登陸。html

sessionStorage顧名思義是針對一個session的數據存儲,生命週期爲當前窗口,一旦窗口關閉,那麼存儲的數據將被清空。最後還有一個很主要的區別同一瀏覽器的相同域名和端口的不一樣頁面間能夠共享相同的 localStorage,可是不一樣頁面間沒法共享sessionStorage的信息。瀏覽器

解決:
在index.html中增長如下代碼,複製所有sessionStorage內資料安全

(function(){
    // 判斷當前頁面是否存在sessionStorage
    if (!sessionStorage.length) {
        // 這個調用能觸發目標事件,從而達到共享數據的目的(若不存在則加上一個localStorage Item,key=getSessionStorageData)
        localStorage.setItem('getSessionStorageData', Date.now());
    };

    // 該事件是核心,增長window監聽事件 
    window.addEventListener('storage', function(event) {
         // 已存在的標籤頁會收到這個事件,若是監聽到的事件key是getSessionStorageData
         if (event.key == 'getSessionStorageData') {
             // 再新增一個localStorage Item,key=sessionStorageData,value就是當前的sessionStorage
            localStorage.setItem('sessionStorage', JSON.stringify(window.sessionStorage));
            // 刪除localStorage中key=sessionStorageData的item
            localStorage.removeItem('sessionStorage');

        } 
        if (event.key == 'sessionStorageData' && !sessionStorage.length) {
            // 新開啓的標籤頁會收到這個事件,把sessionStorageData的資料parse出來
            const data = JSON.parse(event.newValue);
            //  賦值到當前頁面的sessionStorage中
            for (key in data) {
                window.sessionStorage.setItem(key, data[key]);
            }
        }
    });
})();

總體流程:
一、判斷頁面是否存在sessionStorage,並加上store事件的監聽;
二、若不存在,就把本來的sessionStorage內的資料複製到localStorage中並取名爲sessionStorageData;
三、若storage事件監聽到key爲sessionStorageData的事件,就把內容經過for賦值到頁面sessionStorage中;session

爲何複製到localStorage後又直接刪除?
由於window添加了監聽事件工具

window.addEventListener('storage', ..)

這就意味着每次storage事件被觸發的時候都會執行,因此當setItem('sessionStorage')的時候,也會接收到事件,
表明着測試

window.localStorage.removeItem('sessionStorage')

實際上是發生在sessionStorage被寫入以後的事情了,因此能夠同時寫入和刪除,不留下localSorage的記錄。code

新開的頁面爲何會有sessionStorage能夠提供複製?
查詢API(Using the Web Storage API|MDN)後知道,各標籤只要是同域名,有對storage動做時所有都會被連動,storage事件能夠作到同域名的狀態監測。htm

storage事件的測試
隨便開兩個同域名的標籤頁後,分別開啓開發者工具:
一、在A標籤頁下token

window.addEventListener('storage', (event) => console.log(event));

二、在B標籤頁下生命週期

window.localStorage.setItem('storageTest', 'test');

三、再回頭看A標籤頁,就會發現已經被監聽到storage事件了。
經過這樣的事件監聽,就能夠達到由localSorage傳遞sessionStorage的目的。

關於登出
登出時同步清除全部標籤頁的sessionStorage並reload頁面

(function(){
    // 判斷當前頁面是否存在sessionStorage
    if (!sessionStorage.length) {
        // 這個調用能觸發目標事件,從而達到共享數據的目的(若不存在則加上一個localStorage Item,key=getSessionStorageData)
        localStorage.setItem('getSessionStorageData', Date.now());
    };

    // 該事件是核心,增長window監聽事件 
    window.addEventListener('storage', function(event) {
         // 已存在的標籤頁會收到這個事件,若是監聽到的事件key是getSessionStorageData
         if (event.key == 'getSessionStorageData') {
             // 再新增一個localStorage Item,key=sessionStorageData,value就是當前的sessionStorage
            localStorage.setItem('sessionStorage', JSON.stringify(window.sessionStorage));
            // 刪除localStorage中key=sessionStorageData的item
            localStorage.removeItem('sessionStorage');

        } 
        if (event.key == 'sessionStorageData' && !sessionStorage.length) {
            // 新開啓的標籤頁會收到這個事件,把sessionStorageData的資料parse出來
            const data = JSON.parse(event.newValue);
            //  賦值到當前頁面的sessionStorage中
            for (key in data) {
                window.sessionStorage.setItem(key, data[key]);
            }
        }
        // ===== 加下面這段 =====
        if (event.key === 'logout') {
            // 接收到logout事件,進行sessionStorage的清除和頁面reload
            window.sessionStorage.clear();
            window.location.clear();
        }
    });
})();

其餘即便這樣看起來ok,但仍是有缺陷一、Chrome,FireFox的恢復分頁功能會將sessionStorage的資料一塊兒恢復,這可能會致使一些安全性問題(不過相較於localStorage,這應該不算問題)二、這些數據是標籤頁被開啓的同時獲取的,意味着若是你的sessionStorage儲存着常常被變更的資料,必須再寫一些事件去攔截和複製,由於storage事件不會監聽到其餘頁面的sessionStorage變更.

相關文章
相關標籤/搜索