變臉式應用 / 會話重用與自動登錄

自動跳轉登錄頁和會話重用

爲了避免每次打開或刷新應用都要再登錄,會話重用是實現短期免登錄進入的常用方法。

[任務]

  • 打開H5應用時(從任意入口頁進入),如果剛剛登錄過,則可以免登錄直接打開入口頁。
    如果尚未登錄過,則跳轉至登錄頁面,待登錄成功後跳轉到入口頁。
  • 點退出登錄回到首頁,如果首頁必須登錄,則到登錄頁。
  • 在操作過程中,一旦調用某個接口返回了未登錄錯誤(實際中可能是客戶端掉線、服務端重啓等情況),應自動跳轉到登錄頁。

要實現這樣的需求,需要有以下接口設計:

  • 登錄接口login,登錄成功返回用戶信息,例如login(uname, pwd) -> [0, {用戶信息如id, name, ...}].
    登錄接口可以支持多種方式登錄,如用戶名/密碼,手機號/動態驗證碼,以及下一節要講述的自動登錄token等。
  • 其它所有要求用戶登錄後才能調用的接口,在未登錄時返回統一的錯誤碼: fn1() -> [2, "未登錄"](筋斗雲中未登錄錯誤碼爲2)
  • 退出接口logout() -> [0, "OK"].
  • 有一個特別的檢測是否需要登錄的接口,如果已登錄,返回與login接口相同的信息,例如接口User.get() -> [0, {用戶信息如id, name, ...}].

這個特別的檢測登錄接口的主要用途是,通過會話重用(session),實現短時間內免登錄。
會話重用一般由服務端設置cookie實現,由於瀏覽器會自動記住cookie,只要服務端會話未過期且用戶未退出(logout),就可以一直免登錄進入。
即使不使用cookie而用URL參數(比如token)的,H5應用只要自行記住這個token到本地存儲,下次打開時重用即可。

這樣,前端進入H5應用時的邏輯就是:

  • 調用檢測用戶登錄的接口User.get,調用成功後將返回信息存儲到全局變量g_data.userInfo中,並顯示入口頁;
  • 如果調用失敗,則顯示登錄頁;
  • 在登錄成功後,跳轉回一開始要進入的入口頁。

這些邏輯由框架函數MUI.tryAutoLoginMUI.handleLogin提供,應注意把這段邏輯放置到muiInit事件中,以便在顯示任意頁面之前調用。
我們在筋斗雲示例應用中,可以看到這樣的代碼:(index.js中)

$(document).on("muiInit", myInit);

function myInit()
{
    MUI.tryAutoLogin(handleLogin, "User.get");
}

function handleLogin(data)
{
    MUI.handleLogin(data);
    // g_data.userInfo已賦值
}

在MUI.tryAutoLogin中指定了檢查會話重用的接口名爲”User.get”,於是H5應用便有了會話重用的功能。
在模擬接口中,我們看到”User.get”接口模擬如下:

"User.get": [0, user],

這表明模擬的是已登錄過的狀態,因此打開應用時可直接免登錄進入。
我們把它改成返回”未登錄”錯誤:

"User.get": [2, "no auth"],

這時刷新H5應用,是不是進入了登錄頁?
任意輸入手機號和驗證碼可登錄進來。進入頁面”我”,點退出,看看是不是回到了登錄頁?

注意框架定義了“未認證錯誤”缺省錯誤碼爲2,如果要修改,可以用:

window.E_NOAUTH = 2;

再看會話中斷時的行爲,由於進入訂單列表頁會調用接口”Ordr.query”,我們在瀏覽器控制檯上修改模擬接口讓它返回未登錄錯:

MUI.mockData["Ordr.query"] = [2, "no auth"];

進入訂單列表頁(如果之前已經打開過,可以下拉刷新下),看看是不是自動跳轉到登錄頁了?

如果後端接口格式不是使用筋斗雲調用規範,則需要按上節介紹自行適配接口,在其中添加自動跳轉登錄頁的的邏輯,如:

    MUI.callSvrExt['default'] = {
        ...
        dataFilter: function (data) {
            ...
            if (data.code == E_NOAUTH) {
                MUI.showLogin();
                return;
            }
        }
    };

這樣,框架可以確保未登錄時(或已掉線、服務端重啓等情況時)調用了後端需要登錄的接口,可以自動跳轉到登錄頁。

注意:調用MUI.showLogin()來顯示登錄頁,而不要用MUI.showPage("#login")來寫死頁面,而且MUI.showLogin可以在登錄成功後跳回登錄前想進入的頁面。
類似的還有MUI.showHome()來顯示首頁。

上面示例中,用MUI.tryAutoLogin要求進入應用必須先登錄。如果某些入口頁可以免登錄直接進入,則應這樣調用:

function myInit()
{
    MUI.tryAutoLogin(handleLogin, "User.get", true); // 參數true表示允許未登錄進入
}

這時應特別小心,可用g_data.userInfo == null判斷是否爲未登錄。
從未登錄的入口頁進入其它需要登錄才能展示的頁面,也常常在pagebeforeshow事件中添加判斷:

    function onPageBeforeShow(ev, opt)
    {
        // 可能從一個未登錄的頁面跳轉過來
        if (g_data.userInfo == null) {
            MUI.showLogin();
            return;
        }
        // 設置頁面內容
    }

注意:在MUI.tryAutoLogin中調用接口時,都使用的是同步調用且忽略錯誤。

自動登錄

自動登錄是一個常見需求,基本上現在的手機應用,登錄過一次後,下次都是免登錄進入。

前面已經講過通過會話重用,可以實現短時間內免登錄。
通過對cookie設置較長的超時時間,且在後端長期保存會話數據,可以延長免登錄的時間。

如果會話重用機制的實現並不可靠,比如過期、後端過載或重啓等導致會話丟失,最好再設計專門的自動登錄機制。
要實現自動登錄,客戶端必須將登錄信息保存在本地。由於用戶名、密碼這些信息很敏感,不適合直接存儲在客戶端,一般通過token來實現自動登錄。

需要後端login接口支持token,注意token參數要求通過POST參數傳遞的:

login(uname, pwd) -> {_token, ...} // 普通登錄,額外返回_token字段
login()(token) -> {_token?, ...} // 可以不再返回token

與之前的login接口相比,普通的登錄方式可返回一個_token字段,將這個字段保存在客戶端本地,下次就可以通過login(token)方式自動登錄。
服務器在實現時,一般在token中包含了用戶信息,token過期時間等信息,當然進行了加密,所以比較安全。

H5應用要實現的邏輯如下:

  • 進入應用時,先嚐試會話重用,在會話重用失敗後,再嘗試自動登錄
  • 如果在操作過程中用戶掉線(如客戶端長時間未操作導致會話超時),也可通過自動登錄,對用戶透明地實現恢復登錄後繼續操作。

框架已經在MUI.tryAutoLogin函數及默認的後端接口適配中完成以上邏輯,只要服務端接口符合上面約定,無需額外代碼。

我們來模擬接口,讓User.get接口返回未登錄,讓login接口支持返回_token,看看H5應用的行爲:

    "login": function (param, postParam) {
        if (postParam.token) {
            console.log("用token自動登錄");
            return [0, user];
        }
        return [0, $.extend({_token: "abcdefg"}, user)];
    },
    ...
    "User.get": [2, "no auth"],
  • 刷新H5應用,因爲未登錄過,正確進入登錄頁,注意看瀏覽器控制檯的日誌,只調用了”User.get”接口,失敗後轉到登錄頁。
  • 在成功登錄一次後,再次刷新H5應用,發現可以直接進入應用了,看日誌,先調用了”User.get”失敗,然後嘗試自動登錄調用了”login”接口成功。
  • 直到去頁面“我”點擊“退出”,刷新H5應用纔不再自動登錄。

如果是自行適配接口,只需將前面示例中跳轉登錄頁的操作換成嘗試自動登錄,示例如下:

    MUI.callSvrExt['default'] = {
        ...
        dataFilter: function (data) {
            ...
            if (data.code == E_NOAUTH) {
                // 嘗試自動登錄,如果登錄成功則重新發起當前請求;登錄失敗會自動轉向登錄頁
                if (MUI.tryAutoLogin()) {
                    $.ajax(this);
                }
                // MUI.showLogin();
                return;
            }
        }
    };

注意:

上述對會話重用和自動登錄的支持,核心是進入應用時及應用掉線時調用MUI.tryAutoLogin函數,而它是基於筋斗雲後端的接口設計。
如果後端接口設計不同,可自行來寫一個tryAutoLogin函數,在進入應用時及應用掉線時調用。

特別地,在tryAutoLogin中調用接口,一般使用同步調用(選項{async: false}),且忽略出錯(選項{noex:1}):

var opt = {async: false, noex: 1};
callSvr("User.get", $.noop, null, opt);
發佈了65 篇原創文章 · 獲贊 16 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章