一、GET/POST方法簡(jiǎn)介&用戶安全
1、GET/POST方法簡(jiǎn)介
在客戶端和服務(wù)器之間進(jìn)行請(qǐng)求-響應(yīng)時(shí),兩種最常被用到的方法是:GET 和 POST。
> GET - 從指定的資源請(qǐng)求數(shù)據(jù)。
* GET 請(qǐng)求可被緩存,可以保留在瀏覽器歷史記錄中,可被收藏為書簽。
* GET 請(qǐng)求從數(shù)學(xué)角度來講,GET的結(jié)果是 冪等 的
* GET 請(qǐng)求有長(zhǎng)度限制,在HTTP協(xié)議定義中,沒有對(duì)GET請(qǐng)求的數(shù)據(jù)大小限制,不過因?yàn)闉g覽器不同,一般限制在2~8K。
* GET 請(qǐng)求的所有參數(shù)包裝在URL中,并且服務(wù)器的訪問日志會(huì)記錄,不要傳遞敏感信息。
* 參數(shù)格式
>> 在資源路徑末尾添加 ? 表示追加參數(shù)
>> 每一個(gè)變量及值按照? 變量名=變量值 方式設(shè)定,不能包含空格或中文
>> 多個(gè)參數(shù)使用 & 連接
>> URL 字符中如果包含中文,需要添加百分號(hào)轉(zhuǎn)義。
# 在數(shù)學(xué)中,一個(gè)數(shù)多次進(jìn)行該運(yùn)算所得的結(jié)果和進(jìn)行一次該運(yùn)算所得的結(jié)果是一樣的,那么我們就稱該運(yùn)算是冪等的。比如絕對(duì)值運(yùn)算就是一個(gè)例子,在實(shí)數(shù)集中,有abs(a)=abs(abs(a))。
# GET的結(jié)果是 冪等 的,是說對(duì)同一個(gè)URL請(qǐng)求多次獲得的結(jié)果都是一樣的。
> POST - 向指定的資源提交要被處理的數(shù)據(jù)
* POST 請(qǐng)求不會(huì)被緩存,不會(huì)保留在瀏覽器歷史記錄中,不能被收藏為書簽
* POST 向服務(wù)器發(fā)送數(shù)據(jù),也可以獲得服務(wù)器處理之后的結(jié)果,效率不如GET
* POST 提交數(shù)據(jù)比較大,大小靠服務(wù)器的設(shè)定值限制,PHP通常限定2M。
* POST 提交的參數(shù)包裝成二進(jìn)制的數(shù)據(jù)體,格式與 GET 基本一致,只是不包含 ?
* URL中 只有資源路徑,但不包含參數(shù),服務(wù)器日志不會(huì)記錄參數(shù),相對(duì)更安全。
* 所有設(shè)計(jì)用戶隱私的數(shù)據(jù)(密碼,銀行卡號(hào))一定記住使用POST方式傳遞。
2、瀏覽器演示GET/POST請(qǐng)求的區(qū)別。
3、GET緩存實(shí)現(xiàn)
> Request緩存請(qǐng)求頭
* If-None-Match : 與響應(yīng)頭的Etag相對(duì)應(yīng),可以判斷本地緩存數(shù)據(jù)是否發(fā)生變化。
> GET方法緩存演練
/*
1、請(qǐng)求是可變的,緩存策略要每次都從服務(wù)器加載
2、每次得到響應(yīng)后,需要記錄 etag
3、下次發(fā)送請(qǐng)求的同時(shí),將 etag 一起發(fā)送給服務(wù)器,由服務(wù)器比較內(nèi)容有沒有變
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSURL *url = [NSURL URLWithString:@"http://localhost/itcast/images/head1.png"];
//? ? NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
// 傳遞 etag
if (self.etag.length > 0) {
[request setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
}
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"%@,%zd",response,data.length);
// 類型轉(zhuǎn)換(在oc中,如果將父類轉(zhuǎn)換成子類需要強(qiáng)制轉(zhuǎn)換)
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
// 獲取并記錄 etag,區(qū)分大小寫
self.etag = httpResponse.allHeaderFields[@"Etag"];
// 判斷響應(yīng)狀態(tài)碼是否是 304 Not Modified
if (httpResponse.statusCode == 304) {
NSLog(@"加載本地?cái)?shù)據(jù)");
// 如果是,使用本地緩存
// 根據(jù)請(qǐng)求獲得被緩存的響應(yīng)
NSCachedURLResponse *cacheResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
// 拿到緩存的數(shù)據(jù)
data = cacheResponse.data;
}
NSLog(@"etag = %@",self.etag);
self.iconView.image = [UIImage imageWithData:data];
}];
}
> 代碼小結(jié)
* 請(qǐng)求的緩存策略使用NSURLRequestReloadIgnoringCacheData,忽略本地緩存
* 服務(wù)器響應(yīng)結(jié)束后,要記錄 Etag,服務(wù)器內(nèi)容和本地緩存對(duì)比是否變化的重要依據(jù)
* 在發(fā)送請(qǐng)求時(shí),設(shè)置 If-None-Match,并且傳人 Etag
* 連接結(jié)束后,要判斷響應(yīng)頭的狀態(tài)碼,如果是304,說明本地緩存內(nèi)容沒有變化。
4、NSURLCache--設(shè)置緩存
> 在iOS中,可以使用NSURLCache類緩存數(shù)據(jù)
// 設(shè)置網(wǎng)絡(luò)緩存
// 4M 的內(nèi)存緩存
// 20M 的磁盤緩存
// diskPath:緩存路徑? nil:表示使用系統(tǒng)默認(rèn)的緩存路徑:沙盒/Library/Caches
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:@"pkxing"];
// 設(shè)置全局緩存
[NSURLCache setSharedURLCache:cache];
> iOS 5之前:只支持內(nèi)存緩存。從iOS 5開始:同時(shí)支持內(nèi)存緩存和硬盤緩存
# AFNetworking的作者M(jìn)attt說:無數(shù)開發(fā)者嘗試自己做一個(gè)簡(jiǎn)陋而脆弱的系統(tǒng)來實(shí)現(xiàn)網(wǎng)絡(luò)緩存功能,殊不知 NSURLCache 只要兩行代碼就能搞定且好上100倍。
二、用戶登錄
1、GET登錄
> 代碼演示
/**
*? GET方式登錄
*/
- (void)getLogin{
// 創(chuàng)建url
NSString urlStr = [NSString stringWithFormat:@"http://localhost/login.php?username=%@&password=%@",self.userName,self.password];
// 如果url 字符串中,包含中文或空格等特殊字符,需要添加百分號(hào)轉(zhuǎn)義
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
// 創(chuàng)建請(qǐng)求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 請(qǐng)求的默認(rèn)方法就是 GET
NSLog(@"%@",request.HTTPMethod);
// 發(fā)送請(qǐng)求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSLog(@"%@,%@",response,dict);
}];
}
> URL編碼
* Url編碼通常也被稱為百分號(hào)編碼(Url Encoding,also known as percent-encoding),是因?yàn)樗木幋a方式非常簡(jiǎn)單,使用%百分號(hào)加上兩位的字符——0123456789ABCDEF——代表一個(gè)字節(jié)的十六進(jìn)制形式。
* Url編碼默認(rèn)使用的字符集是ASCII
1、 為什么需要編碼?
> url支持26個(gè)英文字母、數(shù)字和少數(shù)幾個(gè)特殊字符,因此,對(duì)于url中包含非標(biāo)準(zhǔn)url的字符時(shí),就需要對(duì)其進(jìn)行編碼。
2、 如何編碼?
NSString urlStr = [NSString stringWithFormat:@"http://localhost/login.php?username=%@&password=%@",self.userName,self.password];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
> GET請(qǐng)求緩存的位置
* GET請(qǐng)求返回的json數(shù)據(jù)緩存在Caches/bundleId/Cache.db的sqlite數(shù)據(jù)庫(kù)中。
* 通過終端查看:進(jìn)入到 Caches.db 所在的文件夾,
> 執(zhí)行命令 sqlite3 Cache.db; 打開數(shù)據(jù)庫(kù)
> 執(zhí)行命令 .tables; 可查看數(shù)據(jù)庫(kù)的表
> 執(zhí)行命令 select * from 表名;可查看對(duì)應(yīng)的表數(shù)據(jù),即緩存內(nèi)容。
2、 POST登錄
/**
*? POST方式登錄
*/
- (void)postLogin{
// 創(chuàng)建url
NSURL *url = [NSURL URLWithString:@"http://localhost/login.php"];
// 創(chuàng)建請(qǐng)求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請(qǐng)求方法為 POST
request.HTTPMethod = @"POST";
// 設(shè)置請(qǐng)求體二進(jìn)制數(shù)據(jù)
NSString *bodyStr = [NSString stringWithFormat:@"username=%@&password=%@",self.userName,self.password];
#warning HTTPBody 和 HTTPBodyStream 只需要設(shè)置其中一個(gè)就行了,如果兩個(gè)都設(shè)置了,前面設(shè)置的就無效了。
//? ? request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBodyStream = [[NSInputStream alloc] initWithData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
// 發(fā)送請(qǐng)求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSLog(@"%@,%@",response,dict);
}];
}
3、POST和GET請(qǐng)求的對(duì)比
> URL對(duì)比
* GET
1、login.php 負(fù)責(zé)登錄的腳本,提示:上課使用的是 php,而工作中不一定,可能是.jsp,asp,aspx...取決于后臺(tái),后臺(tái)提供什么,客戶端就用什么。
2、‘?’ 表示接參數(shù)
3、參數(shù)格式:變量名=值
4、‘&’ 多個(gè)參數(shù)拼接
5、包含中文或空格等特殊字符,需要添加百分號(hào)轉(zhuǎn)義
* POST
只有一個(gè) URL,不包含參數(shù)
> Request對(duì)比
* GET
默認(rèn)方法就是 GET
* POST
1、將字符串轉(zhuǎn)換成二進(jìn)制數(shù)據(jù),設(shè)置HTTPBody或HTTPBodyStream
2、指定 request.HTTPMethod = @"POST"
> Connnection 對(duì)比
* 就是將請(qǐng)求發(fā)送給服務(wù)器,獲得二進(jìn)制數(shù)據(jù)的響應(yīng). GET和POST沒有區(qū)別。
三、模擬登錄
1、搭建界面
2、將數(shù)據(jù)保存到沙盒--用戶名和密碼
> 為什么要保存用戶名和密碼?
# 很多移動(dòng)應(yīng)用,在用戶第一次登錄之后,下次再次使用軟件的時(shí)候都是會(huì)自動(dòng)登錄直接進(jìn)入到應(yīng)用的主界面,要實(shí)現(xiàn)自動(dòng)登錄,就必須在用戶第一次登錄成功后保存用戶的登錄信息。
> 登錄信息保存到哪里?
# 保存到應(yīng)用的沙盒中,偏好設(shè)置里面
# 將用戶信息以明文的方式保存存在很大的安全隱患。
3、安全原則(重要)
> 不能在網(wǎng)絡(luò)上傳輸用戶隱私數(shù)據(jù)的明文。
> 不能在本地存儲(chǔ)用戶隱私數(shù)據(jù)的明文。
四、Base64
參考網(wǎng)站:http://zh.wikipedia.org/wiki/Base64
1、簡(jiǎn)介
> 是網(wǎng)絡(luò)上使用最廣泛的編碼系統(tǒng),能夠?qū)⑷魏味M(jìn)制數(shù)據(jù),轉(zhuǎn)換成只有65個(gè)字符組成的文本文件
> 由 a~z,A~Z,0~9,+,/,=等65個(gè)字符組成
> Base64 編碼后的結(jié)果能夠反算,不夠安全。
> Base64 是所有現(xiàn)代加密算法的基礎(chǔ)算法。
2、原理
-base64的編碼都是按字符串長(zhǎng)度,以每3個(gè)8bit的字符為一組,
-然后針對(duì)每組,首先獲取每個(gè)字符的ASCII編碼,
-然后將ASCII編碼轉(zhuǎn)換成8bit的二進(jìn)制,得到一組3*8=24bit的字節(jié)
-然后再將這24bit劃分為4個(gè)6bit的字節(jié),并在每個(gè)6bit的字節(jié)前面都填兩個(gè)高位0,得到4個(gè)8bit的字節(jié)
-然后將這4個(gè)8bit的字節(jié)轉(zhuǎn)換成10進(jìn)制,對(duì)照Base64編碼表,得到對(duì)應(yīng)編碼后的字符。
注:如果被編碼字符長(zhǎng)度不是3的倍數(shù)的時(shí)候,則都用0代替,對(duì)應(yīng)的輸出字符為=
//參考文章 http://www.cnblogs.com/hongru/archive/2012/01/14/2321397.html
3> 終端命令
# 將 abc.png 進(jìn)行 base64編碼,生成 xxx.txt 文件
$ base64 abc.png -o xxx.txt? // -o 表示輸出
# 將 xxx.txt 解碼生成1.png
$ base64 -D xxx.txt -o 1.png // -D 表示 decoder 解碼
# 將字符串 ABC 進(jìn)行 base64 編碼
$ echo -n ABC | base64
# 將字符串 QUJD 解碼
$ echo -n QUJD | base64 -D
五、Base64代碼實(shí)現(xiàn)
#pragma mark - Base64
// 編碼:A => QQ==
-(NSString *)base64Encode:(NSString *)string{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
// 解碼:QQ== => A
- (NSString *)base64Decode:(NSString *)string {
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
1、修改代碼
> 保存密碼不能使用明文,使用 base64進(jìn)行加密。
> 提交數(shù)據(jù)到服務(wù)器不能使用明文,使用 base64進(jìn)行加密。
六、MD5加密實(shí)現(xiàn)
1、什么是MD5?
* Message Digest Algorithm MD5(中文名為消息摘要算法第五版)是計(jì)算機(jī)安全領(lǐng)域廣泛使用的一種散列函數(shù)(也叫Hash函數(shù)),用以提供消息的完整性保護(hù)。
2、MD5算法具有以下特點(diǎn)
> 壓縮性:任意長(zhǎng)度的數(shù)據(jù),算出的MD5值長(zhǎng)度都是固定的。相同的字符串,每次MD5后的結(jié)果是固定的。
> 容易計(jì)算:從原數(shù)據(jù)計(jì)算出MD5值很容易。
> 抗修改性:對(duì)原數(shù)據(jù)進(jìn)行任何改動(dòng),哪怕只修改1個(gè)字節(jié),所得到的MD5值都有很大區(qū)別。
> 弱抗碰撞:已知原數(shù)據(jù)和其MD5值,想找到一個(gè)具有相同MD5值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的。
> 強(qiáng)抗碰撞:想找到兩個(gè)不同的數(shù)據(jù),使它們具有相同的MD5值,是非常困難的。
3、MD5的作用?
> 一致性驗(yàn)證
我們都知道,地球上任何人都有自己獨(dú)一無二的指紋,這常常成為司法機(jī)關(guān)鑒別罪犯身份最值得信賴的方法。與之類似,通過MD5就可以為任何文件(不管其大小、格式、數(shù)量)產(chǎn)生一個(gè)獨(dú)一無二的"數(shù)字指紋",如果任何人對(duì)文件做了任何改動(dòng),其MD5值也就是對(duì)應(yīng)的"數(shù)字指紋"都會(huì)發(fā)生變化。
具體來說文件的MD5值就像是這個(gè)文件的“數(shù)字指紋”。每個(gè)文件的MD5值是不同的,如果任何人對(duì)文件做了任何改動(dòng),其MD5值也就是對(duì)應(yīng)的“數(shù)字指紋”就會(huì)發(fā)生變化。比如下載服務(wù)器針對(duì)一個(gè)文件預(yù)先提供一個(gè)MD5值,用戶下載完該文件后,用這個(gè)算法重新計(jì)算下載文件的MD5值,通過比較這兩個(gè)值是否相同,就能判斷下載的文件是否出錯(cuò),或者說下載的文件是否被篡改了。
利用MD5算法來進(jìn)行文件校驗(yàn)的方案被大量應(yīng)用到軟件下載站、論壇數(shù)據(jù)庫(kù)、系統(tǒng)文件安全等方面。
> 數(shù)字簽名
MD5的典型應(yīng)用是對(duì)一段Message(字節(jié)串)產(chǎn)生fingerprint(指紋)以防止被“篡改”。
舉個(gè)例子:
你將一段話寫在一個(gè)叫readme.txt文件中,并對(duì)這個(gè)readme.txt產(chǎn)生一個(gè)MD5的值并記錄在案,然后
你可以傳播這個(gè)文件給別人,別人如果修改了文件中的任何內(nèi)容,你對(duì)這個(gè)文件重新計(jì)算MD5時(shí)就會(huì)發(fā)現(xiàn)(
兩個(gè)MD5值不相同)。如果再有一個(gè)第三方的認(rèn)證機(jī)構(gòu),用MD5還可以防止文件作者的“抵賴”,這就是所謂
的數(shù)字簽名應(yīng)用。
> 安全訪問認(rèn)證
典型案例:加密用戶登錄密碼。
當(dāng)用戶登錄的時(shí)候,系統(tǒng)把用戶輸入的密碼進(jìn)行MD5 Hash運(yùn)算,然后再去和保存在文件系統(tǒng)中的MD5值
進(jìn)行比較,進(jìn)而確定輸入的密碼是否正確。通過這樣的步驟,系統(tǒng)在并不知道用戶密碼的明碼的情況下就
可以確定用戶登錄系統(tǒng)的合法性。這可以避免用戶的密碼被具有系統(tǒng)管理員權(quán)限的用戶知道。
4、MD5加密實(shí)現(xiàn)
/*
對(duì)密碼進(jìn)行 MD5 加密 - 不安全
NSString *password = self.passField.text.md5String;
NSString *password = self.passField.text.md5String.md5String;
*/
> 如何使MD5加密更安全?
1、加鹽、現(xiàn)在用的比較少,前兩年用得比較多。
// 準(zhǔn)備鹽
static NSString *salt = @"fadsfdbvcxweioa4321asfFAFA321DSFASDF%$%$^$^$$#@23123124{}{4";
NSString *password = [self.passField.text stringByAppendingString:salt].md5String;
注意點(diǎn):‘鹽’在現(xiàn)實(shí)生活中是佐料,就是給密碼加點(diǎn)料,salt要夠咸(復(fù)雜點(diǎn)的字符串)。
2、用HMac。 HMAC運(yùn)算利用哈希算法,以一個(gè)密鑰和一個(gè)消息為輸入,生成一個(gè)消息摘要作為輸出。
下面代碼 md5的過程:使用密鑰itheima對(duì)密碼加密,加密后做md5,得到32位字符串,再次使用 itheima 加密,再md5。
HMAC現(xiàn)在使用的比較廣泛,安全級(jí)別更高, 破解難度高。
但還是有風(fēng)險(xiǎn):每次結(jié)果一致,有可能被暴力破解。
要想做到的安全級(jí)別更更高,現(xiàn)在密碼學(xué)要求:同樣的算法,同樣的密碼明文,每次的結(jié)果不一樣。
NSString *password = [self.passField.text hmacMD5StringWithKey:@"itheima"];
5、使用時(shí)間戳,目前使用非常廣泛
/**
*? 生成帶時(shí)間戳的密碼
*/
- (NSString *)timePassword{
// 1.設(shè)置密鑰 key
NSString *key = @"itheima".md5String;
// 2.對(duì)密鑰key對(duì)密碼進(jìn)行HMac
NSString *pwd = [self.passField.text hmacMD5StringWithKey:key];
NSLog(@"key = %@",key);
// 3.獲得當(dāng)前的系統(tǒng)時(shí)間
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 指定時(shí)區(qū),真機(jī)通常需要指定時(shí)區(qū)
fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh"];
// 設(shè)置時(shí)間格式
fmt.dateFormat = @"yyyy-MM-dd HH:mm";
// 格式化當(dāng)前時(shí)間
NSString *dateStr = [fmt stringFromDate:[NSDate date]];
// 4.用密碼 + 時(shí)間 生成 密碼
pwd = [pwd stringByAppendingString:dateStr];
// 5.返回 hmac 結(jié)果
return [pwd hmacMD5StringWithKey:key];
}
NSString *password = [self timePassword];
#MD5在線查詢網(wǎng)站://http://www.cmd5.com/
6、獲得服務(wù)器時(shí)間,生成帶時(shí)間戳的密碼
- (NSString *)timePassword{
// 1.設(shè)置密鑰 key
NSString *key = @"itheima".md5String;
// 2.對(duì)密鑰key對(duì)密碼進(jìn)行HMac
NSString *pwd = [self.passField.text hmacMD5StringWithKey:key];
// 3.獲得當(dāng)前服務(wù)器的系統(tǒng)時(shí)間
NSURL *url = [NSURL URLWithString:@"http://localhost/hmackey.php"];
// 使用同步獲取時(shí)間(注意:這里要使用同步,確定先獲得服務(wù)器的時(shí)間,后面的代碼才能執(zhí)行)
NSData *timeData = [NSData dataWithContentsOfURL:url];
// 反序列化取出時(shí)間
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:timeData options:0 error:NULL];
NSString *dateStr = dict[@"key"];
// 4.用密碼 + 時(shí)間 生成 密碼
pwd = [pwd stringByAppendingString:dateStr];
// 5.返回 hmac 結(jié)果
return [pwd hmacMD5StringWithKey:key];
}
> 為什么要獲得服務(wù)器時(shí)間來對(duì)密碼進(jìn)行hmac?
# 有些人是走在時(shí)間的前面的,他手機(jī)上的時(shí)間設(shè)置會(huì)比真實(shí)的時(shí)間的快5分鐘。如果是這樣的,就會(huì)導(dǎo)致客戶端獲得的系統(tǒng)時(shí)間和服務(wù)器獲得的系統(tǒng)時(shí)間相差幾分鐘。那就會(huì)導(dǎo)致 hmac 的結(jié)果不一致,無法登錄。
七、鑰匙串訪問
#使用MD5加密本地密碼有個(gè)問題:
MD5是不可逆的,本地使用MD5加密密碼保存到偏好設(shè)置的時(shí)候,無法再讀取的時(shí)候載解析成
原來的文字。而使用 Base64加密又太過簡(jiǎn)單了,容易破解。這時(shí)候就要使用鑰匙串了。
1、鑰匙串
> 鑰匙串訪問,使用 AES 256加密算法,能夠保證用戶密碼的安全。
> 鑰匙串訪問SDK,是蘋果ios7.0.3 版本以后發(fā)布的
> 鑰匙串訪問的接口是純C語(yǔ)言的,但是,網(wǎng)絡(luò)上有個(gè)哥們把它封裝成 OC的,使用相當(dāng)簡(jiǎn)單!
> 鑰匙串訪問的密碼保存在哪里?
* 只有蘋果知道,是為了進(jìn)一步保障用戶的密碼安全。
> 鑰匙串訪問的第三方框架,是對(duì) C 框架的封裝,可以不用看源代碼
2、框架地址:https://github.com/samsoffes/sskeychain
3、代碼實(shí)現(xiàn)
// 保存用戶登錄信息
- (void)saveUserInfo{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:self.nameField.text forKey:HMUsernameKey];
// 保存到密碼到鑰匙串
/**
參數(shù):
1.密碼‘明文’,加密工作蘋果做了,使用的是 AES 256 算法
2.服務(wù)名,可以隨便寫,建議使用bundleId
3.帳號(hào),用戶名。因?yàn)殍€匙串訪問中,可以保存很多帳號(hào),很多app的密碼
*/
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
[SSKeychain setPassword:self.passField.text forService:bundleId account:self.nameField.text];
}
// 加載用戶登錄信息
- (void)loadUserInfo{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.nameField.text = [defaults valueForKey:HMUsernameKey];
// 從鑰匙串中獲得密碼
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
self.passField.text = [SSKeychain passwordForService:bundleId account:self.nameField.text];
}
八、登錄代碼抽取
1、代碼重構(gòu)
> 應(yīng)用程序開發(fā)中,通常會(huì)建立一個(gè)網(wǎng)絡(luò)請(qǐng)求管理的單例,管理所有的網(wǎng)絡(luò)請(qǐng)求,這樣可以很好的控制并發(fā)數(shù)。
> 將用戶登錄部分代碼抽取到單例管理,簡(jiǎn)化控制器的代碼。
* 誰(shuí)調(diào)用登錄方法最合適? AppDelegate
* 復(fù)制 ‘加載用戶信息方法’ 到單例對(duì)象中
* 在 init 方法中加載用戶信息
> 登錄成功,就直接顯示主界面。
2、登錄界面切換
> 如果監(jiān)聽用戶登錄成功?
* 代理/通知/block/KVO(監(jiān)聽對(duì)象屬性變化)
代理是一對(duì)一的,在單例中不要使用代理。
通知是多對(duì)多的,這種情況選擇通知。
3、注銷切換界面