Saturday, April 27, 2013

oAuth авторизация в iOS http://blog.zakovinko.com/2012/04/oauth-ios.html

http://blog.zakovinko.com/2012/04/oauth-ios.html

oAuth авторизация в iOS

Нашел хорошую библиотечку, в которой реализована поддержка oAuth 1 & oAuth 2 для iOS/Mac OS. К сожалению, документации по ней нет, зато есть демка использования, в которой реализована поддержка авторизации для twitter, facebook, flickr, qq.

Далее расскажу как я делал авторизацию LinkedIn с ее помощью.

Создаем новый проект "Single View Application", у меня он будет называться "LinkedInAuth".

Подключаем зависимости:

Теперь нужно указать дополнительные флаги линкеру (это требует ytoolkit).

  • открываем "Build Settings"
  • в разделе "Linking" находим "Other Linker Flags" и добавляем туда "-all_load" и "-ObjC" (если вы не видите "Other Linker Flags" переключите отображение списка на "All")

Нам нужен класс в проекте, в котором будут хранится ключ и секрет от LinkedIn'а. Для этого добавляем новый "Objective-C class" под названием "AuthCredentials", унаследованный от "NSObject". Мы потом уберем обьявленый Xcode'ом интерфейс.

В "AuthCredentials.h" обявлием константы kLinkedInKey и kLinkedInSecret:

#import <Foundation/Foundation.h>  #import <ytoolkit/ydefines.h>    YEXTERN NSString * const kLinkedInKey;  YEXTERN NSString * const kLinkedInSecret;  

А в "AuthCredentials.m" указываем значения наших констант:

#import "AuthCredentials.h"    NSString * const kLinkedInKey = @"сюда вписываем ключ";  NSString * const kLinkedInSecret = @"а сюда секрет )";  

Добавляем в проект новый "Objective-C class", который назовем "AuthViewController" и наследуем от "UIViewController". Также не забываем поставить галку "With XIB for user interface".

Открываем AuthViewController.h и приводим его вот к такому виду:

#import <UIKit/UIKit.h>  #import <ytoolkit/ydefines.h>  #import "ASIHTTPRequest.h"    @class AuthViewController;    @protocol AuthViewControllerDelegate  - (void)authViewControllerDidFinish:(AuthViewController *)controller;  @end    @interface AuthViewController : UIViewController <UIWebViewDelegate, ASIHTTPRequestDelegate>    @property (assign, nonatomic) id<AuthViewControllerDelegate> delegate;  @property (retain, nonatomic) IBOutlet UIWebView *webView;  @property (copy, nonatomic) NSString *accesstoken;  @property (copy, nonatomic) NSString *tokensecret;  @property (copy, nonatomic) NSString *verifier;  @property (copy, nonatomic) NSString *step; // нужен что бы в будующем понимать на каком шаге авторизации мы находимся    - (IBAction)done:(id)sender;    @end  

Открываем AuthViewController.xib, добавляем на него WebView и привязываем к нашему webView(с зажатым "control" тянем связть от "File's Owner" до "WebView" и из выпавшего списка выбираем "webView") и в обратном порядке выбирая delegate.

Теперь можно перейти к самой большой части, непосредственно к функционалу авторизации через LinkedIn для этого открываем наш AuthViewController.m и добавляем в него код.

Для начала прописываем нужные импорты:

#import "ASIHTTPRequest+YOAuthv1Request.h"  #import "AuthCredentials.h"  #import "SBJson/SBJson.h"  #import <ytoolkit/ymacros.h>  #import <ytoolkit/ycocoaadditions.h>  #import <ytoolkit/yoauthadditions.h>  

В "viewDidLoad" начинам процедуру авторизации:

// создаем запрос  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://api.linkedin.com/uas/oauth/requestToken"]];  request.delegate = self; // указываем что мы будем обрабатывать ответ  [request setRequestMethod:@"POST"]; // тип запроса POST  // вызываем функцию подготовки запроса, которая добавит нужные параметры в url  [request prepareOAuthv1AuthorizationHeaderUsingConsumerKey:kLinkedInKey                                           consumerSecretKey:kLinkedInSecret                                                       token:nil                                                 tokenSecret:nil                                             signatureMethod:YOAuthv1SignatureMethodHMAC_SHA1                                                       realm:nil                                                    verifier:nil                                                    callback:@"http://linkedinauth"]; // линк нашего приложения  self.step = @"0"; // это первый шаг  [request startAsynchronous];  

Добавляем метод который покажет ошибку если она произошла:

- (void)requestFailed:(ASIHTTPRequest *)request {      UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"LinkedIn Auth"                                                       message:[request.error localizedDescription]                                                      delegate:nil                                             cancelButtonTitle:@"OK"                                             otherButtonTitles:nil]                            autorelease];      [alert show];  }  

И обработчик вернувшегося запроса:

- (void)requestFinished:(ASIHTTPRequest *)request {      NSDictionary *params = [request.responseString decodedUrlencodedParameters];      self.accesstoken = [params objectForKey:YOAuthv1OAuthTokenKey]; // забираем токены      self.tokensecret = [params objectForKey:YOAuthv1OAuthTokenSecretKey];            if (self.accesstoken && self.tokensecret) {          if ([self.step isEqualToString:@"0"]) {         // если есть токены и это первый шаг, то открываем страницу авторизации LinekdIn в нашем WebView              NSString *url = [NSString stringWithFormat:@"https://www.linkedin.com/uas/oauth/authorize?%@=%@", YOAuthv1OAuthTokenKey, self.accesstoken];              NSMutableURLRequest *r = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];              [self.webView loadRequest:r];          } else {              // если шаг не первый, то завершаем процесс авторизации              [self.delegate authViewControllerDidFinish:self];          }      }  }  

Теперь ловим обновление WebView:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {      NSURL *url = request.URL;      NSString *s = [url absoluteString];      NSString *host = [url host];            // если загружаемый урл принадлежит нашему приложению      if ([host isEqualToString:@"linkedinauth"]) {          NSDictionary *params = [s queryParameters];          // проверяем не заприщен ли доступ          if ([params objectForKey:@"denied"] == nil) {              self.verifier = [params objectForKey:YOAuthv1OAuthVerifierKey]; // сохраняем верификационный код              ASIHTTPRequest *r = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://api.linkedin.com/uas/oauth/accessToken"]];              [r setRequestMethod:@"POST"];              r.delegate = self;              // отправляем запрос авторизации наших токенов              [r prepareOAuthv1AuthorizationHeaderUsingConsumerKey:kLinkedInKey                                                 consumerSecretKey:kLinkedInSecret                                                             token:self.accesstoken                                                       tokenSecret:self.tokensecret                                                   signatureMethod:YOAuthv1SignatureMethodHMAC_SHA1                                                             realm:nil                                                          verifier:self.verifier                                                          callback:nil];              self.step = @"1"; // дальше пошел второй шаг              [r startAsynchronous];          } else {              NSString *deniedMsg = [NSString stringWithFormat:@"authorize denied: %@", [params objectForKey:@"denied"]];              UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:[[self class] description]                                                               message:deniedMsg                                                              delegate:nil                                                     cancelButtonTitle:@"OK"                                                     otherButtonTitles:nil]                                    autorelease];              [alert show];          }                    return NO;      }            return YES;  }  

Вот собственно и все. Осталось только сохранить полученные нами токены. Для этого мы в "ViewController.h" добавляем объявление переменных, импорт контролера авторизации и делегирование AuthViewControllerDelegate:

#import <UIKit/UIKit.h>  #import "AuthViewController.h"    @interface ViewController : UIViewController <AuthViewControllerDelegate>    @property (strong, nonatomic) NSString *accesstoken;  @property (strong, nonatomic) NSString *tokensecret;    @end  

Сохранение полученных значений в "ViewController.m":

- (void)authViewControllerDidFinish:(AuthViewController *)controller {      self.accesstoken = controller.accesstoken;      self.tokensecret = controller.tokensecret;      [self dismissModalViewControllerAnimated:YES];  }  


Исходный код: скачать

No comments:

Post a Comment