iOS實現OAuth2.0中重新整理access token並重新請求資料操作,iosoauth2.0
一、簡要概述
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。
二、應用情境
使用者登入後,服務端會發行一個有效時間的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、微博等用戶端中尤為常見。
三、執行個體代碼
(1)此類繼承了AFNetworking中的AFHTTPSessionManager類,並重寫了裡面的方法。
NetWorkCallBack.h:
1 #import <Foundation/Foundation.h>2 #import <AFNetworking.h>3 @interface NetWorkCallBack : AFHTTPSessionManager4 5 @end
NetWorkCallBack.m:
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到期,返回錯誤,調用此block14 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發送給伺服器,以擷取新的token56 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