03-GET,POST,用戶登錄

一、HTTP常用方法

  • 在客戶端和服務(wù)器之間進行請求-響應(yīng)時,兩種最常被用到的方法是:GET 和 POST瘾杭。
  • 瀏覽器演示GET/POST請求的區(qū)別粥烁。
  • 控制臺查看服務(wù)器訪問日志,觀察 GET 和 POST 請求的區(qū)別芥永。

1埋涧、GET 請求

  • GET - 從指定的URL獲取資源數(shù)據(jù)。

    • GET 請求可被緩存耳标,可以保留在瀏覽器歷史記錄中呼猪,可被收藏為書簽。
    • GET 請求從數(shù)學(xué)角度來講谚赎,GET的結(jié)果是 冪等 的
    • GET 請求有長度限制,在HTTP協(xié)議定義中视粮,沒有對GET請求的數(shù)據(jù)大小限制,不過因為瀏覽器不同钓觉,一般限制在2~8K。
    • GET 請求的所有參數(shù)包裝在URL中础锐,并且服務(wù)器的訪問日志會記錄皆警,不要傳遞敏感信息。
  • 名詞解析

    • 冪等
      • 在數(shù)學(xué)中意推,一個數(shù)多次進行該運算所得的結(jié)果和進行一次該運算所得的結(jié)果是一樣的靡羡,那么我們就稱該運算是冪等的略步。比如絕對值運算就是一個例子绽诚,在實數(shù)集中,有abs(a)=abs(abs(a))蜂桶。
      • GET的結(jié)果是 冪等 的,是說對同一個URL請求多次獲得的結(jié)果都是一樣的疆股。
  • GET請求參數(shù)格式

    • 在資源路徑末尾添加 ? 表示追加參數(shù)
    • 每一個變量及值按照 變量名=變量值 方式設(shè)定,不能包含空格或中文
    • 多個參數(shù)使用 & 連接
    • URL 字符中如果包含中文,需要添加百分號轉(zhuǎn)義卷雕。

2、POST 請求

  • POST - 向指定的資源提交要被處理的數(shù)據(jù)
    • POST 請求不會被緩存,不會保留在瀏覽器歷史記錄中,不能被收藏為書簽
    • POST 向服務(wù)器發(fā)送數(shù)據(jù),也可以獲得服務(wù)器處理之后的結(jié)果,效率不如GET
    • POST 提交數(shù)據(jù)比較大,大小由服務(wù)器的設(shè)定值限制,PHP通常限定2M。
    • POST 提交的參數(shù)包裝成二進制的數(shù)據(jù)體,格式與 GET 基本一致,只是不包含 ?
    • URL中 只有資源路徑,但不包含參數(shù),服務(wù)器日志不會記錄參數(shù),相對更安全魁蒜。
    • 所有設(shè)計用戶隱私的數(shù)據(jù)(密碼,銀行卡號)一定記住使用POST方式傳遞。

3吩翻、GET 緩存

  • 1兜看、提問:為什么 GET 請求可以被緩存,而 POST 請求不被緩存狭瞎?
    答:GET 的結(jié)果是冪等的细移,同一個 URL 每次的請求結(jié)果都是一樣的,基于這個特點熊锭,GET 請求就可以被緩存起來避免每次對同一個 URL 請求都要訪問服務(wù)器碗殷,可以節(jié)省用戶流量和提供響應(yīng)速度。而 POST請求的結(jié)果一般都是不一樣的,比如用戶登錄仿吞,每個用戶登錄獲得的信息都是不一樣的,基于這個特點蒿褂,POST 請求的結(jié)果不會被緩存。

  • 2、GET 緩存實現(xiàn)

    • Request緩存請求頭

      • If-None-Match : 與響應(yīng)頭的Etag相對應(yīng)干厚,可以判斷本地緩存數(shù)據(jù)是否發(fā)生變化。
    • 如何實現(xiàn) get緩存?

      • 請求是可變的蒙谓,緩存策略要每次都從服務(wù)器加載
      • 每次得到響應(yīng)后毒租,需要記錄 etag
      • 下次發(fā)送請求的同時灾梦,將 etag 一起發(fā)送給服務(wù)器鲫忍,由服務(wù)器比較內(nèi)容有沒有變
    • 代碼實現(xiàn)如下

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    NSURL *url = [NSURL URLWithString:@"[http://localhost/itcast/images/head1.png](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)換成子類需要強制轉(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(@"加載本地數(shù)據(jù)");

            // 如果是,使用本地緩存
            // 根據(jù)請求獲得被緩存的響應(yīng)
            NSCachedURLResponse *cacheResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];

            // 拿到緩存的數(shù)據(jù)
            data = cacheResponse.data;
        }

        NSLog(@"etag = %@",self.etag);

        self.iconView.image = [UIImage imageWithData:data];
    }];
}
  • 3肯腕、代碼小結(jié)
    • 請求的緩存策略使用NSURLRequestReloadIgnoringCacheData贡茅,忽略本地緩存。
    • 服務(wù)器響應(yīng)結(jié)束后,要記錄 Etag,服務(wù)器內(nèi)容和本地緩存對比是否變化的重要依據(jù)搅轿。
    • 在發(fā)送請求時,設(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開始:同時支持內(nèi)存緩存和硬盤緩存
# AFNetworking的作者Mattt說:無數(shù)開發(fā)者嘗試自己做一個簡陋而脆弱的系統(tǒng)來實現(xiàn)網(wǎng)絡(luò)緩存功能,殊不知 NSURLCache 只要兩行代碼就能搞定且好上100倍饵逐。

二括眠、用戶登錄

  • 安全原則
    • 不能在網(wǎng)絡(luò)上傳傳輸用戶隱私數(shù)據(jù)的明文
    • 不能在本地存儲用戶隱私數(shù)據(jù)的明文

1、GET登錄

- (void)getLogin{
       // 創(chuàng)建url
/**
     url擴展:
     1倍权、login.php 負(fù)責(zé)登錄的腳本,提示:上課使用的是 php,而工作中不一定,可能是.jsp,asp,aspx...取決于后臺,后臺提供什么,客戶端就用什么掷豺。
     2、‘?’ 表示接參數(shù)
     3薄声、參數(shù)格式:變量名=值
     4当船、‘&’ 多個參數(shù)拼接
     */
    NSString urlStr = [NSString stringWithFormat:@"http://localhost/login.php?username=%@&password=%@",self.userName,self.password];
    // 如果url 字符串中,包含中文或空格等特殊字符默辨,需要添加百分號轉(zhuǎn)義
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 創(chuàng)建請求
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 請求的默認(rèn)方法就是 GET
        // GET 效率高,使用頻率高的訪問  建議是用GET! POST一般用來發(fā)送訂單德频,個人隱私數(shù)據(jù),上傳文件....
    NSLog(@"%@",request.HTTPMethod);
    // 發(fā)送請求
    [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);
    }];
}
  • 1.1、URL編碼

    • 為什么需要編碼?

      • url支持26個英文字母缩幸、數(shù)字和少數(shù)幾個特殊字符,因此,對于url中包含非標(biāo)準(zhǔn)url的字符時,就需要對其進行編碼壹置。
    • Url編碼通常也被稱為百分號編碼(Url Encoding,also known as percent- encoding),是因為它的編碼方式非常簡單,使用%百分號加上兩位的字 符——0123456789ABCDEF——代表一個字節(jié)的十六進制形式竞思。

    • Url編碼默認(rèn)使用的字符集是ASCII

  • 1.2、如何編碼

NSString urlStr = [NSString stringWithFormat:@"http://localhost/login.php?username=% @&password=%@",self.userName,self.password];

// 如果url 字符串中,包含中文或空格等特殊字符,需要添加百分號轉(zhuǎn)義
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  • 1.3钞护、GET請求緩存的位置
    • 驗證 GET 請求返回的 json 數(shù)據(jù)被緩存起來了盖喷。

      • 把請求對象的緩存策略改為:NSURLRequestReturnCacheDataDontLoad。只從緩存加載患亿。再次運行程序看有沒結(jié)果返回传蹈。
      • 停止 apache 服務(wù)器:再次運行程序看有沒結(jié)果返回。
        • 停止命令:sudo apachectl -k stop;
        • 重啟命令:sudo apachectl -k restart;
        • 開啟命令:sudo apachectl -k start;
    • GET請求返回的json數(shù)據(jù)緩存在Caches/bundleId/Cache.db的sqlite數(shù)據(jù)庫中步藕。

      • 通過終端查看:進入到 Caches.db 所在的文件夾
      • 執(zhí)行命令 sqlite3 Cache.db; 打開數(shù)據(jù)庫
      • 執(zhí)行命令 .tables; 可查看數(shù)據(jù)庫的表
      • 執(zhí)行命令 select * from 表名;可查看對應(yīng)的表數(shù)據(jù),即緩存內(nèi)容
    • 友情提示

      • 現(xiàn)在只需要知道緩存的位置就行了惦界,后續(xù)的課程會介紹數(shù)據(jù)庫相關(guān)的知識。

2咙冗、POST登錄

  • 代碼實現(xiàn)
- (void)postLogin{
    // 創(chuàng)建url,不需要添加百分號轉(zhuǎn)義(內(nèi)部已經(jīng)實現(xiàn))
    NSURL *url = [NSURL URLWithString:@"http://localhost/login.php"];
    // 創(chuàng)建請求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 設(shè)置請求方法為 POST
    request.HTTPMethod = @"POST";
    // 設(shè)置請求體二進制數(shù)據(jù)
    NSString *bodyStr = [NSString stringWithFormat:@"username=%@&password=%@",self.userName,self.password];
    //    request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
    request.HTTPBodyStream = [[NSInputStream alloc] initWithData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
    // 發(fā)送請求
    [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);
    }];
}
  • 如何查看請求體的格式沾歪?

    • 可以借助火狐瀏覽器和firebug插件。獲得使用瀏覽器登錄時要發(fā)送請求體的格式雾消。
    • 火狐瀏覽器幾乎是每一個做網(wǎng)絡(luò)開發(fā)的程序員必備的一款神器灾搏。它有兩個顯著的特點:
      • 性能很差,速度很慢立润。
      • 插件非常多狂窑。各種調(diào)試插件。
  • 設(shè)置請求體注意點

    • HTTPBody 和 HTTPBodyStream 只需要設(shè)置其中一個就行了,如果兩個都設(shè)置了,前面設(shè)置的就無效了桑腮。

3泉哈、GET和POST 請求對比

  • URL 對比

    • GET

      • login.php 負(fù)責(zé)登錄的腳本。
        • 提示:上課使用的是 php,而工作中不一定,可能是.jsp,asp,aspx...取決于后臺,后臺提供什么,客戶端就用什么破讨。
      • ‘?’ 表示接參數(shù)丛晦。參數(shù)格式:變量名=值。
      • ‘&’表示 多個參數(shù)拼接提陶。
      • 包含中文或空格等特殊字符烫沙,需要添加百分號轉(zhuǎn)義。
    • POST

      • 只有一個 URL隙笆,不包含參數(shù)锌蓄。
  • Request 對比

    • GET:默認(rèn)方法就是 GET。
    • POST
      • 將字符串轉(zhuǎn)換成二進制數(shù)據(jù),設(shè)置HTTPBody或HTTPBodyStream
      • 指定 request.HTTPMethod = @"POST"
  • Connnection 對比

    • 就是將請求發(fā)送給服務(wù)器撑柔,獲得二進制數(shù)據(jù)的響應(yīng)煤率、 GET和POST沒有區(qū)別。

三乏冀、模擬登錄

1、搭建界面

  • 友情提示和細(xì)節(jié)處理

    • 在移動應(yīng)用中洋只,絕大多數(shù)的登錄界面不需要記住登錄密碼控件辆沦。
    • 在使用自動布局時昼捍,如果一組相關(guān)的控件包在一個大的控件中,只需要對外面大的控件添加布局約束就可以了肢扯。
    • 根據(jù)傳統(tǒng)網(wǎng)頁應(yīng)用程序的特點妒茬,用戶按回車鍵時,下一個文本輸入框應(yīng)該獲得焦點蔚晨。
  • 實現(xiàn)登錄邏輯

    • 連線獲得用戶名和密碼文本輸入框乍钻。
    • 監(jiān)聽登錄按鈕的點擊。
      • 使用 post 請求登錄

2铭腕、保存登錄信息

  • 登錄成功后保存用戶名和密碼银择。
  • 程序啟動的時候加載用戶名和密碼。
#define HMUsernameKey @"HMUsernameKey"
#define HMPasswordKey @"HMPasswordKey"
  • 保存用戶登錄信息
- (void)saveUserInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:self.nameField.text forKey:HMUsernameKey];
    [defaults setObject:self.passField.text forKey:HMPasswordKey];
}
  • 加載用戶登錄信息
- (void)loadUserInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.nameField.text = [defaults valueForKey:HMUsernameKey];
    self.passField.text = [defaults valueForKey:HMPasswordKey];
}
  • 友情提示
    在 iOS8.0 之后累舷,就不需要同步了浩考。

四、Base64

1被盈、簡介

參考網(wǎng)站:http://zh.wikipedia.org/wiki/Base64

  • 是網(wǎng)絡(luò)上使用最廣泛的編碼系統(tǒng)析孽,能夠?qū)⑷魏味M制數(shù)據(jù),轉(zhuǎn)換成只有65個字符組成的文本文件只怎。
  • 由 az袜瞬,AZ,0~9身堡,+邓尤,/,= 等65個字符組成盾沫。
  • Base64 編碼后的結(jié)果能夠反算裁赠,不夠安全。
  • Base64 是所有現(xiàn)代加密算法的基礎(chǔ)算法赴精。

2佩捞、原理

參考文章:http://www.cnblogs.com/hongru/archive/2012/01/14/2321397.html

  • base64的編碼都是按字符串長度,以每3個8bit的字符為一組蕾哟,
  • 然后針對每組一忱,首先獲取每個字符的ASCII編碼,
  • 然后將ASCII編碼轉(zhuǎn)換成8bit的二進制谭确,得到一組3*8=24bit的字節(jié)
  • 然后再將這24bit劃分為4個6bit的字節(jié)帘营,并在每個6bit的字節(jié)前面都填兩個高位0,得到4個8bit的字節(jié)
  • 然后將這4個8bit的字節(jié)轉(zhuǎn)換成10進制,對照Base64編碼表,得到對應(yīng)編碼后的字符逐哈。

注:如果被編碼字符長度不是3的倍數(shù)的時候芬迄,則都用0代替,對應(yīng)的輸出字符為=

ABC
01000001 01000010 01000011
010000 010100 001001 000011
16 20 9 3
QUJD

AB
01000001 01000010
010000 010100 001000
16 20 8
QUI=

A
010000 010000
16 16
QQ==

Base64對照表

3昂秃、終端命令

# 將 abc.png 進行 base64編碼,生成 xxx.txt 文件
$ base64 abc.png -o xxx.txt // -o 表示輸出

# 將 xxx.txt 解碼生成1.png
$ base64 -D xxx.txt -o 1.png // -D 表示 decoder 解碼

# 將字符串 ABC 進行 base64 編碼
$ echo -n ABC | base64

# 將字符串 QUJD 解碼
$ echo -n QUJD | base64 -D

4禀梳、Base64代碼實現(xiàn)

  • 1杜窄、修改代碼
    • 保存密碼不能使用明文,使用base64進行加密算途。
    • 提交數(shù)據(jù)到服務(wù)器不能使用明文塞耕,使用base64進行加密。
#pragma mark - Base64
// 編碼:A => QQ==
-(NSString *)base64Encode:(NSString *)string{
    // 1.將字符串轉(zhuǎn)換成二進制數(shù)據(jù)
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    // 2.利用 ios7.0的方法嘴瓤,直接 base64 編碼
    return [data base64EncodedStringWithOptions:0];
}
// 解碼:QQ== => A
- (NSString *)base64Decode:(NSString *)string {
    // 1.將 base64編碼后的字符串扫外,解碼成二進制數(shù)據(jù)
    // 這里不能使用注釋掉的方法轉(zhuǎn)換成二進制,因為 string 就是已經(jīng)編碼過的字符串
    //    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    // 2.返回解碼的字符串
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

五、MD5加密

1廓脆、MD5是什么

Message Digest Algorithm MD5(中文名為消息摘要算法第五版)是計算機安全領(lǐng)域廣泛使用的一種散列函數(shù)(也叫Hash函數(shù))筛谚,用以提供消息的完整性保護。其核心思想是從給定的數(shù)據(jù)中提取特征碼狞贱,不容產(chǎn)生重復(fù)刻获。加密后的字符串通常被稱為指紋或消息摘要。 32位

  • 知識擴展:特征碼有什么作用瞎嬉?

  • 舉例:百度網(wǎng)盤
    上傳文件到百度網(wǎng)盤的時候蝎毡,有時候會發(fā)現(xiàn)上傳速度非常快氧枣,幾秒鐘幾個 G 的文件就上傳上去了沐兵,其內(nèi)部實現(xiàn)的原理是根據(jù)給每個文件一個特征碼來實現(xiàn)的,百度服務(wù)器會為每一個上傳的文件生成一個特征碼便监,后續(xù)用戶上傳文件時會檢測網(wǎng)盤里面是否已經(jīng)有相同特征碼的文件扎谎,如果有,就直接拿過來用了烧董,相當(dāng)于引用計數(shù)加一毁靶,如果有人刪除了,則引用計數(shù)減一逊移,知道所有人都刪除了预吆,文件才會真正從百度服務(wù)器刪掉。

2胳泉、MD5算法特點

  • 壓縮性:任意長度的數(shù)據(jù)拐叉,算出的MD5值長度都是固定的。相同的字符串扇商,每次MD5后的結(jié)果是固定的凤瘦。都是32個字符
  • 容易計算:從原數(shù)據(jù)計算出MD5值很容易。
  • 抗修改性:對原數(shù)據(jù)進行任何改動案铺,哪怕只修改1個字節(jié)蔬芥,所得到的MD5值都有很大區(qū)別。
  • 弱抗碰撞:已知原數(shù)據(jù)和其MD5值,想找到一個具有相同MD5值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的坝茎。
  • 強抗碰撞:想找到兩個不同的數(shù)據(jù)涤姊,使它們具有相同的MD5值,是非常困難的嗤放。
  • 不可逆性:不能逆運算。不可破解壁酬。

3次酌、MD5的作用

  • 一致性驗證

    • 我們都知道,地球上任何人都有自己獨一無二的指紋,這常常成為司法機關(guān)鑒別罪犯身份最值得信賴的方法舆乔。與之類似岳服,通過MD5就可以為任何文件(不管其大小、格式希俩、數(shù)量)產(chǎn)生一個獨一無二的"數(shù)字指紋"吊宋,如果任何人對文件做了任何改動,其MD5值也就是對應(yīng)的"數(shù)字指紋"都會發(fā)生變化颜武。
    • 具體來說文件的MD5值就像是這個文件的“數(shù)字指紋”璃搜。每個文件的MD5值是不同的,如果任何人對文件做了任何改動鳞上,其MD5值也就是對應(yīng)的“數(shù)字指紋”就會發(fā)生變化这吻。比如下載服務(wù)器針對一個文件預(yù)先提供一個MD5值,用戶下載完該文件后篙议,用這個算法重新計算下載文件的MD5值唾糯,通過比較這兩個值是否相同,就能判斷下載的文件是否出錯鬼贱,或者說下載的文件是否被篡改了移怯。
    • 利用MD5算法來進行文件校驗的方案被大量應(yīng)用到軟件下載站、論壇數(shù)據(jù)庫这难、系統(tǒng)文件安全等方面舟误。
  • 數(shù)字簽名

    • MD5的典型應(yīng)用是對一段Message(字節(jié)串)產(chǎn)生fingerprint(指紋)以防止被“篡改”。
      舉個例子:
      你將一段話寫在一個叫readme.txt文件中雁佳,并對這個readme.txt產(chǎn)生一個MD5的值并記錄在案脐帝,然后你可以傳播這個文件給別人,別人如果修改了文件中的任何內(nèi)容糖权,你對這個文件重新計算MD5時就會發(fā)現(xiàn)(兩個MD5值不相同)堵腹。如果再有一個第三方的認(rèn)證機構(gòu),用MD5還可以防止文件作者的“抵賴”,這就是所謂的數(shù)字簽名應(yīng)用星澳。
  • 安全訪問認(rèn)證

    • 典型案例:加密用戶登錄密碼疚顷。
      當(dāng)用戶登錄的時候,系統(tǒng)把用戶輸入的密碼進行MD5 Hash運算,然后再去和保存在文件系統(tǒng)中的MD5值進行比較腿堤,進而確定輸入的密碼是否正確阀坏。通過這樣的步驟,系統(tǒng)在并不知道用戶密碼的明碼的情況下就可以確定用戶登錄系統(tǒng)的合法性笆檀。這可以避免用戶的密碼被具有系統(tǒng)管理員權(quán)限的用戶知道忌堂。

4、MD5加密實現(xiàn)

  • 代碼實現(xiàn)
NSString *password = self.passField.text.md5String; // 執(zhí)行一次 MD5
NSString *password = self.passField.text.md5String.md5String; // 執(zhí)行兩次 MD5
  • 對密碼進行 MD5 加密 - 不安全

  • 如何使MD5加密更安全?

    • 加鹽酗洒、現(xiàn)在用的比較少士修,前兩年用得比較多。
// 準(zhǔn)備鹽
static NSString *salt = @"fadsfdbvcxweioa4321asfFAFA321DSFASDF%$%$^$^$$#@23123124{}{4";
NSString *password = [self.passField.text stringByAppendingString:salt].md5String;

溫馨提示:‘鹽’在現(xiàn)實生活中是佐料,就是給密碼加點料樱衷,salt要夠咸(復(fù)雜點的字符串)棋嘲。
  • 用HMac:HMAC運算利用哈希算法,以一個密鑰和一個消息為輸入矩桂,生成一個消息摘要作為輸出沸移。
    NSString *password = [self.passField.text hmacMD5StringWithKey:@"itheima"];
    上面代碼 md5 的過程:使用密鑰 itheima 對密碼加密,加密后做md5侄榴,得到32位字符串雹锣,再次使用 itheima 加密,再md5牲蜀。

    • HMAC現(xiàn)在使用的比較廣泛笆制,安全級別更高, 破解難度高。
    • 但還是有風(fēng)險:每次結(jié)果一致涣达,有可能被暴力破解在辆。
  • 要想做到的安全級別更更高,現(xiàn)在密碼學(xué)要求:同樣的算法度苔,同樣的密碼明文匆篓,每次的結(jié)果不一樣。

5寇窑、生成帶時間戳的密碼

使用時間戳,目前使用非常廣泛

  • 使用客戶端時間生成帶時間戳的密碼
- (NSString *)timePassword{

    // 1.設(shè)置密鑰 key

    NSString *key = @"itheima".md5String;

    // 2.使用密鑰key對密碼進行HMac

    NSString *pwd = [self.passField.text hmacMD5StringWithKey:key];

    NSLog(@"key = %@",key);

    // 3.獲得當(dāng)前的系統(tǒng)時間

    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];

    // 指定時區(qū)鸦概,真機通常需要指定時區(qū)

    fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh"];

    // 設(shè)置時間格式

    fmt.dateFormat = @"yyyy-MM-dd HH:mm";

    // 格式化當(dāng)前時間

    NSString *dateStr = [fmt stringFromDate:[NSDate date]];

    

    // 4.用密碼 + 時間 生成 密碼

    pwd = [pwd stringByAppendingString:dateStr];

    // 5.返回 hmac 結(jié)果

    return [pwd hmacMD5StringWithKey:key];

}

NSString *password = [self timePassword];
  • 使用服務(wù)器時間,生成帶時間戳的密碼
- (NSString *)timePassword{
    // 1.設(shè)置密鑰 key
    NSString *key = @"itheima".md5String;
    // 2.對密鑰key對密碼進行HMac
    NSString *pwd = [self.passField.text hmacMD5StringWithKey:key];
    
    // 3.獲得當(dāng)前服務(wù)器的系統(tǒng)時間
    NSURL *url = [NSURL URLWithString:@"http://localhost/hmackey.php"];
    // 使用同步獲取時間(注意:這里要使用同步,確定先獲得服務(wù)器的時間,后面的代碼才能執(zhí)行)
    NSData *timeData = [NSData dataWithContentsOfURL:url];
    // 反序列化取出時間
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:timeData options:0 error:NULL];
    NSString *dateStr = dict[@"key"];

    // 4.用密碼 + 時間 生成 密碼
    pwd = [pwd stringByAppendingString:dateStr];
    // 5.返回 hmac 結(jié)果
    return [pwd hmacMD5StringWithKey:key];
}
  • 問題解答:
    • 為什么要獲得服務(wù)器時間來對密碼進行hmac?
      有些人是走在時間的前面的,他手機上的時間設(shè)置會比真實的時間的快5分鐘。如果是這樣的,就會導(dǎo)致客戶端獲得的系統(tǒng)時間和服務(wù)器獲得的系統(tǒng)時 間相差幾分鐘甩骏。那就會導(dǎo)致 hmac 的結(jié)果不一致,無法登錄窗市。

6、其他

破解網(wǎng)站:http://www.cmd5.com

六饮笛、鑰匙串訪問

  • 使用MD5加密本地密碼有個問題
    MD5是不可逆的,本地使用MD5加密密碼保存到偏好設(shè)置的時候,無法再讀取的時候載解析成 原來的文字咨察。而使用 Base64加密又太過簡單了,容易破解。這時候就要使用鑰匙串了福青。

1摄狱、鑰匙串簡介

  • 鑰匙串訪問,使用 AES 256加密算法,能夠保證用戶密碼的安全脓诡。
  • 鑰匙串訪問SDK,是蘋果ios7.0.3 版本以后發(fā)布的
  • 鑰匙串訪問的接口是純C語言的,但是,網(wǎng)絡(luò)上有個哥們把它封裝成 OC的,使用相當(dāng)簡單!
  • ? 鑰匙串訪問的第三方框架,是對C框架的封裝,可以不用看源代碼
  • 框架地址:https://github.com/samsoffes/sskeychain

2、代碼實現(xiàn)

  • 保存用戶登錄信息
- (void)saveUserInfo{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setValue:self.nameField.text forKey:HMUsernameKey];

    // 保存到密碼到鑰匙串

    /**
     參數(shù):
     1.密碼‘明文’媒役,加密工作蘋果做了祝谚,使用的是 AES 256 算法
     2.服務(wù)名,可以隨便寫酣衷,建議使用bundleId
     3.帳號交惯,用戶名。因為鑰匙串訪問中鸥诽,可以保存很多帳號商玫,很多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];
}
  • 鑰匙串訪問的密碼保存在哪里?
    只有蘋果知道,是為了進一步保障用戶的密碼安全。

七牡借、重構(gòu)登錄代碼

// 登錄成功通知
#define HMLoginSuccessNotification @"HMLoginSuccessNotification"

@interface HMNetworkTools : NSObject
/**
 *  全局訪問點,用來獲取單列對象
 */
+(instancetype)sharedTools;
/**
 *  登錄
 */
- (void)loginFailed:(void (^)())failed;

/**
 *  用戶名
 */
@property(nonatomic,copy) NSString *username;
/**
 *  密碼
 */
@property(nonatomic,copy) NSString *pwd;
@end

@implementation HMNetworkTools
/**
 *  全局訪問點袭异,用來獲取單列對象
 */
+(instancetype)sharedTools{
    static id instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (instancetype)init {
    if (self = [super init]) {
        [self loadUserInfo];
    }
    return self;
}

/**
 *  登錄
 */
- (void)loginFailed:(void (^)())failed{
    NSAssert(failed != nil, @"必須傳入回調(diào)");
    // 判斷用戶名或密碼是否有值
    if(!(self.username.length > 0 && self.pwd.length > 0)){
        failed();
        return;
    }
    NSString *password = [self timePassword];
    NSLog(@"發(fā)送的密碼=%@",password);
    // 創(chuàng)建url
    NSURL *url = [NSURL URLWithString:@"http://localhost/loginhmac.php"];
    // 創(chuàng)建請求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url ];
    // 設(shè)置請求方法為 POST
    request.HTTPMethod = @"POST";
    // 設(shè)置請求體二進制數(shù)據(jù)
    NSString *bodyStr = [NSString stringWithFormat:@"username=%@&password=%@",_username,password];
    request.HTTPBodyStream = [[NSInputStream alloc] initWithData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
    // 發(fā)送請求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
        if([dict[@"userId"] intValue] > 0) {
            // 登錄成功钠龙,保存用戶信息
            [self saveUserInfo];
            // 發(fā)送通知
            [[NSNotificationCenter defaultCenter] postNotificationName:HMLoginSuccessNotification object:@"Main"];
        } else {
             failed();
        }
    }];
}


#pragma mark - 私有方法

/**
 *  生成帶時間戳的密碼
 */
- (NSString *)timePassword{
    // 1.設(shè)置密鑰 key
    NSString *key = @"itheima".md5String;
    // 2.對密鑰key對密碼進行HMac
    NSString *pwd = [self.pwd hmacMD5StringWithKey:key];
    
    // 3.獲得當(dāng)前服務(wù)器的系統(tǒng)時間
    NSURL *url = [NSURL URLWithString:@"http://localhost/hmackey.php"];
    // 使用同步獲取時間
    NSData *timeData = [NSData dataWithContentsOfURL:url];
    // 反序列化取出時間
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:timeData options:0 error:NULL];
    NSString *dateStr = dict[@"key"];
    // 4.用密碼 + 時間 生成 密碼
    pwd = [pwd stringByAppendingString:dateStr];
    // 5.返回 hmac 結(jié)果
    return [pwd hmacMD5StringWithKey:key];
}


#pragma mark - 保存和加載用戶信息
#define HMUsernameKey @"HMUsernameKey"
#define HMPasswordKey @"HMPasswordKey"
/**
 *  保存用戶登錄信息
 */
- (void)saveUserInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:self.username forKey:HMUsernameKey];
    
    NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
    [SSKeychain setPassword:self.pwd forService:bundleId account:self.username];
}

/**
 *  加載用戶登錄信息
 */
- (void)loadUserInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    self.username = [defaults valueForKey:HMUsernameKey];
    // 從鑰匙串中獲得密碼
    NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
    self.pwd = [SSKeychain passwordForService:bundleId account:self.username];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市御铃,隨后出現(xiàn)的幾起案子碴里,更是在濱河造成了極大的恐慌,老刑警劉巖上真,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咬腋,死亡現(xiàn)場離奇詭異,居然都是意外死亡睡互,警方通過查閱死者的電腦和手機根竿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來就珠,“玉大人寇壳,你說我怎么就攤上這事∑拊酰” “怎么了壳炎?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逼侦。 經(jīng)常有香客問我匿辩,道長,這世上最難降的妖魔是什么榛丢? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任铲球,我火速辦了婚禮,結(jié)果婚禮上涕滋,老公的妹妹穿的比我還像新娘睬辐。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布溯饵。 她就那樣靜靜地躺著侵俗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丰刊。 梳的紋絲不亂的頭發(fā)上隘谣,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音啄巧,去河邊找鬼寻歧。 笑死,一個胖子當(dāng)著我的面吹牛秩仆,可吹牛的內(nèi)容都是我干的码泛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼澄耍,長吁一口氣:“原來是場噩夢啊……” “哼噪珊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齐莲,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤痢站,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后选酗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阵难,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年芒填,在試婚紗的時候發(fā)現(xiàn)自己被綠了呜叫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡氢烘,死狀恐怖怀偷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情播玖,我是刑警寧澤椎工,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蜀踏,受9級特大地震影響维蒙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜果覆,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一颅痊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧局待,春花似錦斑响、人聲如沸菱属。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纽门。三九已至,卻和暖如春营罢,著一層夾襖步出監(jiān)牢的瞬間赏陵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工饲漾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝙搔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓考传,卻偏偏與公主長得像吃型,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子僚楞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理败玉,服務(wù)發(fā)現(xiàn),斷路器镜硕,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 一、GET/POST方法簡介&用戶安全 1返干、GET/POST方法簡介 在客戶端和服務(wù)器之間進行請求-響應(yīng)時,兩種最...
    方圓十里不留母狗閱讀 31,910評論 0 13
  • 一兴枯、概念(載錄于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434閱讀 8,353評論 6 152
  • 有人會認(rèn)為哲學(xué)是遠(yuǎn)在天邊而不可及的東西,事實真是如此嗎矩欠? 我看到的一個較好的解釋是: 哲學(xué)是不用學(xué)就擺在那里的東西...
    williamhyw閱讀 790評論 3 6
  • 媳婦呵斥我睡覺的時候已經(jīng)是十二點以后了财剖,老同學(xué)結(jié)婚前夜,按著習(xí)俗前一天晚上要“賀事情”癌淮。恰好我又是同學(xué)們眼里的老司...
    心甲閱讀 255評論 3 1