前言
一般APP都是剛安裝后,第一次啟動時需要登錄(提示你需要登錄或者直接啟動在登錄界面)。而只要登錄成功后,以后每次啟動時都是登錄狀態,不需要每次啟動時再次登錄。不過,也有些APP若你長期未啟動,再次啟動時,它會提示你登錄過期,讓你重新登錄。這個是怎么實現的?APP是怎么保持登錄狀態的?
之所以突然寫這個話題,是因為昨晚無意間刷知乎刷到了這個問題 iOS系統如何實現app登錄類似微信只需登錄一次,退出后不需要每次登錄?
回答里給出了好幾種解決方案,其中比較標準的方案是 “帶時效檢測的token機制” 。所謂 token
,即“令牌”的意思。那這個token機制的執行邏輯是怎么樣的呢?
token機制
token機制的執行邏輯可以用下面一張圖展示清楚:
flowsheet.JPG
當用戶剛安裝完APP,并進行了注冊,擁有了賬號和密碼后。此時,則該進行首次登錄了:
APP將用戶輸入的賬號和密碼提交給服務器;
服務器對其進行校驗,若賬號和密碼對得上則校驗通過,說明登錄成功。并生成一個 token
值,將其保存在數據庫,同時也返回給客戶端;
客戶端拿到返回的 token
值后,可將其保存在本地。作為公共參數,即以后每次請求服務器時都攜帶該 token
,提交給服務器,讓服務器校驗。
服務器接收到請求后,會取出請求頭里的 token
值與數據庫存儲的 token
進行對比校驗。若兩個 token
值相同,則說明用戶登錄成功過,且當前正處于登錄狀態,此時正常返回數據,讓APP顯示數據。若兩個值不一致,則說明原來的的登錄已經失效,此時返回錯誤狀態碼,提示用戶跳轉至登錄界面重新登錄。
用戶每進行一次登錄,登錄成功后服務器都會更新個 token
新值返回給客戶端。
基本的邏輯原理就是這些,下面我們看看項目代碼中具體是怎么寫的。
代碼
首先看在登錄界面發送登錄請求那塊。一開始我以為服務器返回的 token
值會在響應數據體中,也就是和用戶信息在一起。但是我看了接口,并沒有發現與 token
對應的字段。后來仔細看了下代碼,原來 token
是在響應頭中的。上面邏輯里的無論是存儲 token
值,還是攜帶 token
作為公共參數,都是在網絡層完成的。這一切都發生在網絡層,而不麻煩業務層,這很優雅。
每當登錄成功后,服務器在響應頭中返回新的 token
值,將其保存在本地:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { _httpResponse = (NSHTTPURLResponse *)response; if(_httpResponse amp;amp; [_httpResponse respondsToSelector:@selector(allHeaderFields)]) { NSDictionary *httpResponseHeaderFields = [_httpResponse allHeaderFields]; NSNumber *totle=[NSNumber numberWithLongLong:[[httpResponseHeaderFields objectForKey:@quot;Content-Lengthquot;] longLongValue]]; _dataSize=[totle integerValue]; if (_requestInterface == RequestInterfaceLogin ||_requestInterface == RequestInterfaceVerifyCodeLogin || _requestInterface == RequestInterfaceRegister) {//設置token NSString *tokenString = httpResponseHeaderFields[@quot;x-auth-tokenquot;]; [REDUserModel saveToken:tokenString]; RUNDUG(@quot;token------%@quot;,tokenString); } } }
(void)saveToken:(NSString *)token { if (token.length == 0) { return; } [[NSUserDefaults standardUserDefaults]setObject:token forKey:kTokenKey]; [[NSUserDefaults standardUserDefaults] synchronize]; }
除了在成功登錄的回調方法里存儲 token
值外,也可以在內存和磁盤存儲一個登錄狀態,表示是否是登錄狀態。下次啟動APP時,我只需要從本地獲取該值,看其是登錄狀態否?然后決定界面怎么顯示,或者點擊界面上的按鈕去執行什么事件,是去完成業務動作,還是彈出登錄界面讓用戶重新登錄。
(這個可以寫在網絡層的回調方法里,也可以寫在業務層的回調方法里,都沒問題。)
[REDUserModel shareInstance].isLogin = YES; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kUserLoginStatus]; [[NSUserDefaults standardUserDefaults] synchronize];
在每次發送非登錄請求接口時,將 token
作為公共參數放入請求頭中提交給服務器,服務器對其進行校驗,判斷是登錄狀態否?還是太久未登錄需要重新登錄。然后返回相應的狀態碼。
if (interface != RequestInterfaceLogin) { [_request setValue:[REDUserModel shareInstance].token forHTTPHeaderField:@quot;x-auth-tokenquot;]; }
結尾
總結,用 token
機制完成登錄狀態保持/身份認證,生成怎樣的 token
,怎么進行 token
校驗都是服務器完成的。其實客戶端的工作很簡單,就是保存服務器給的 token
,然后將其作為請求服務器的公共參數。
Tags: iOS開發
文章來源:http://www.jianshu.com/p/8d28e60af440