token機(jī)制完成登錄狀態(tài)保持/身份認(rèn)證

前言

一般APP都是剛安裝后,第一次啟動(dòng)時(shí)需要登錄(提示你需要登錄或者直接啟動(dòng)在登錄界面)。而只要登錄成功后,以后每次啟動(dòng)時(shí)都是登錄狀態(tài),不需要每次啟動(dòng)時(shí)再次登錄。不過,也有些APP若你長期未啟動(dòng),再次啟動(dòng)時(shí),它會(huì)提示你登錄過期,讓你重新登錄。這個(gè)是怎么實(shí)現(xiàn)的?APP是怎么保持登錄狀態(tài)的?

之所以突然寫這個(gè)話題,是因?yàn)樽蛲頍o意間刷知乎刷到了這個(gè)問題iOS系統(tǒng)如何實(shí)現(xiàn)app登錄類似微信只需登錄一次,退出后不需要每次登錄?
回答里給出了好幾種解決方案,其中比較標(biāo)準(zhǔn)的方案是“帶時(shí)效檢測的token機(jī)制”。所謂token,即“令牌”的意思。那這個(gè)token機(jī)制的執(zhí)行邏輯是怎么樣的呢?


token機(jī)制

token機(jī)制的執(zhí)行邏輯可以用下面一張圖展示清楚:

flowsheet.JPG

當(dāng)用戶剛安裝完APP,并進(jìn)行了注冊,擁有了賬號(hào)和密碼后。此時(shí),則該進(jìn)行首次登錄了:

APP將用戶輸入的賬號(hào)和密碼提交給服務(wù)器;
服務(wù)器對(duì)其進(jìn)行校驗(yàn),若賬號(hào)和密碼對(duì)得上則校驗(yàn)通過,說明登錄成功。并生成一個(gè)token值,將其保存在數(shù)據(jù)庫,同時(shí)也返回給客戶端;
客戶端拿到返回的token值后,可將其保存在本地。作為公共參數(shù),即以后每次請(qǐng)求服務(wù)器時(shí)都攜帶該token,提交給服務(wù)器,讓服務(wù)器校驗(yàn)。
服務(wù)器接收到請(qǐng)求后,會(huì)取出請(qǐng)求頭里的token值與數(shù)據(jù)庫存儲(chǔ)的token進(jìn)行對(duì)比校驗(yàn)。若兩個(gè)token值相同,則說明用戶登錄成功過,且當(dāng)前正處于登錄狀態(tài),此時(shí)正常返回?cái)?shù)據(jù),讓APP顯示數(shù)據(jù)。若兩個(gè)值不一致,則說明原來的的登錄已經(jīng)失效,此時(shí)返回錯(cuò)誤狀態(tài)碼,提示用戶跳轉(zhuǎn)至登錄界面重新登錄。

用戶每進(jìn)行一次登錄,登錄成功后服務(wù)器都會(huì)更新個(gè)token新值返回給客戶端。

基本的邏輯原理就是這些,下面我們看看項(xiàng)目代碼中具體是怎么寫的。


代碼

首先看在登錄界面發(fā)送登錄請(qǐng)求那塊。一開始我以為服務(wù)器返回的token值會(huì)在響應(yīng)數(shù)據(jù)體中,也就是和用戶信息在一起。但是我看了接口,并沒有發(fā)現(xiàn)與token對(duì)應(yīng)的字段。后來仔細(xì)看了下代碼,原來token是在響應(yīng)頭中的。上面邏輯里的無論是存儲(chǔ)token值,還是攜帶token作為公共參數(shù),都是在網(wǎng)絡(luò)層完成的。這一切都發(fā)生在網(wǎng)絡(luò)層,而不麻煩業(yè)務(wù)層,這很優(yōu)雅。

每當(dāng)?shù)卿洺晒?,服?wù)器在響應(yīng)頭中返回新的token值,將其保存在本地:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    
    _httpResponse = (NSHTTPURLResponse *)response;
    if(_httpResponse && [_httpResponse respondsToSelector:@selector(allHeaderFields)])
    {    
        NSDictionary *httpResponseHeaderFields = [_httpResponse allHeaderFields];
        NSNumber *totle=[NSNumber numberWithLongLong:[[httpResponseHeaderFields objectForKey:@"Content-Length"] longLongValue]];
        _dataSize=[totle integerValue];
        
        if (_requestInterface == RequestInterfaceLogin ||_requestInterface == RequestInterfaceVerifyCodeLogin ||  _requestInterface == RequestInterfaceRegister) {//設(shè)置token
            NSString *tokenString = httpResponseHeaderFields[@"x-auth-token"];
            [REDUserModel saveToken:tokenString];

            RUNDUG(@"token------%@",tokenString);
        }
    }
}
+ (void)saveToken:(NSString *)token
{
    if (token.length == 0) {
        return;
    }
    [[NSUserDefaults standardUserDefaults]setObject:token forKey:kTokenKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

除了在成功登錄的回調(diào)方法里存儲(chǔ)token值外,也可以在內(nèi)存和磁盤存儲(chǔ)一個(gè)登錄狀態(tài),表示是否是登錄狀態(tài)。下次啟動(dòng)APP時(shí),我只需要從本地獲取該值,看其是登錄狀態(tài)否?然后決定界面怎么顯示,或者點(diǎn)擊界面上的按鈕去執(zhí)行什么事件,是去完成業(yè)務(wù)動(dòng)作,還是彈出登錄界面讓用戶重新登錄。
(這個(gè)可以寫在網(wǎng)絡(luò)層的回調(diào)方法里,也可以寫在業(yè)務(wù)層的回調(diào)方法里,都沒問題。)

    [REDUserModel shareInstance].isLogin = YES;

    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kUserLoginStatus];
    [[NSUserDefaults standardUserDefaults] synchronize];

在每次發(fā)送非登錄請(qǐng)求接口時(shí),將token作為公共參數(shù)放入請(qǐng)求頭中提交給服務(wù)器,服務(wù)器對(duì)其進(jìn)行校驗(yàn),判斷是登錄狀態(tài)否?還是太久未登錄需要重新登錄。然后返回相應(yīng)的狀態(tài)碼。

    if (interface != RequestInterfaceLogin) {
        [_request setValue:[REDUserModel shareInstance].token forHTTPHeaderField:@"x-auth-token"];
    }```

---

# 結(jié)尾
總結(jié),用``token``機(jī)制完成登錄狀態(tài)保持/身份認(rèn)證,生成怎樣的``token``,怎么進(jìn)行``token``校驗(yàn)都是服務(wù)器完成的。其實(shí)客戶端的工作很簡單,就是保存服務(wù)器給的``token``,然后將其作為請(qǐng)求服務(wù)器的公共參數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容