1、簡要概述json
OAuth2.0是OAuth協議的下一版本,時經常使用於移動客戶端的開發,是一種比較安全的機制。在OAuth 2.0中,server將發行一個短有效期的access token和長生命期的refresh token。這將容許客戶端無需用戶再次操做而獲取一個新的access token,而且也限制了access token的有效期。即當sever發送的access token過時以後,客戶端會調用方法,將access token和refresh token發送給服務端,服務端將會返回新的access token和refresh token。安全
2、應用場景服務器
用戶登陸後,服務端會發行一個有效時間的access token,同時也會發行一個長生命期的refresh token。用戶在進行其餘網絡請求時,會把access token加入請求體中(並不須要加入refresh token)。若是在請求過程當中,access token過時,返回相應的狀態碼。這時就回調用一個回調方法,在回調方法體中將原來的access token和refresh token發送給服務端,獲取新的access token和refresh token。而後把新的access token加入剛纔的請求體中,從新加載網絡請求。微信
限定access token的有效時間,只是爲了提升安全性。access token過時後從新獲取並從新加載請求這一操做,用戶是察覺不到的。這種機制在微信、QQ、微博等客戶端中尤其常見。網絡
3、實例代碼app
(1)此類繼承了AFNetworking中的AFHTTPSessionManager類,並重寫了裏面的方法。async
NetWorkCallBack.h:url
1 #import <Foundation/Foundation.h>
2 #import <AFNetworking.h>
3 @interface NetWorkCallBack : AFHTTPSessionManager 4
5 @end
NetWorkCallBack.m:spa
1 #import "NetWorkCallBack.h"
2 #import <SSKeychain.h>
3 @implementation NetWorkCallBack 4
5 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSMutableURLRequest *)urlRequest completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))originalCompletionHandler{ 6
7 //create a completion block that wraps the original
8 void (^authFailBlock)(NSURLResponse *response, id responseObject, NSError *error) = ^(NSURLResponse *response, id responseObject, NSError *error) 9 { 10 NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 11 if([httpResponse statusCode] == 401){ 12
13 //若是access token過時,返回錯誤,調用此block
14 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 15
16 //調用refreshAccesstoken方法,刷新access token。
17 [self refreshAccessToken:^(AFHTTPRequestOperation *operation) { 18 //存取新的access token,此處我使用了KeyChain存取
19 NSDictionary *headerInfo = operation.response.allHeaderFields; 20 NSString *newAccessToken = [headerInfo objectForKey:@"access-token"]; 21 NSString *newRefreshToken = [headerInfo objectForKey:@"refresh-token"]; 22 [SSKeychain deletePasswordForService:@"<key>" account:@"access-token"]; 23 [SSKeychain deletePasswordForService:@"<key>" account:@"refresh-token"]; 24 [SSKeychain setPassword:newAccessToken forService:@"<key>" account:@"access-token"]; 25 [SSKeychain setPassword:newRefreshToken forService:@"<key>" account:@"refresh-token"]; 26
27 //將新的access token加入到原來的請求體中,從新發送請求。
28 [urlRequest setValue:newAccessToken forHTTPHeaderField:@"access-token"]; 29
30 NSURLSessionDataTask *originalTask = [super dataTaskWithRequest:urlRequest completionHandler:originalCompletionHandler]; 31 [originalTask resume]; 32 }]; 33 }); 34 }else{ 35 NSLog(@"no auth error"); 36 originalCompletionHandler(response, responseObject, error); 37 } 38 }; 39
40 NSURLSessionDataTask *stask = [super dataTaskWithRequest:urlRequest completionHandler:authFailBlock]; 41
42 return stask; 43
44 }; 45
46
47 /*
48 *獲取新的token的方法。如何獲取能夠自定義,我這裏用了AFNetWorking的AFHTTPRequestOperation類 49 */
50 -(void)refreshAccessToken:(void(^)(AFHTTPRequestOperation *responseObject))refresh{ 51 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:@"<yourURL>"]; 52
53 [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 54
55 //將原來的access token和refresh token發送給服務器,以獲取新的token
56 NSString *accessToken = [SSKeychain passwordForService:@"<key>" account:@"access-token"]; 57 NSString *refreshToken = [SSKeychain passwordForService:@"<key>" account:@"refresh-token"]; 58
59 [request setValue:accessToken forHTTPHeaderField:@"access-token"]; 60 [request setValue:refreshToken forHTTPHeaderField:@"refresh-token"]; 61
62 //執行網絡方法
63 AFHTTPRequestOperation *httpRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 64 [httpRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation * operation, id responseObject) { 65 refresh(operation); 66 } failure:^(AFHTTPRequestOperation * operation, NSError * error) { 67 refresh(operation); 68 }]; 69 [httpRequestOperation start]; 70 } 71 @end