oAuth авторизация в iOS
Нашел хорошую библиотеку, в которой реализована поддержка oAuth 1 & oAuth 2 для iOS/Mac OS. К сожалению, документации по ней нет, зато есть демка использования, в которой реализована поддержка авторизации для twitter, facebook, flickr, qq.
Далее расскажу как я делал авторизацию LinkedIn с ее помощью.
Создаем новый проект “Single View Application”, у меня он будет называться “LinkedInAuth”.
Подключаем зависимости:
- непосредственно обсуждаемая библиотека (https://github.com/sprhawk/ytoolkit.git)
- SBJson для парсинга json (https://github.com/stig/json-framework.git)
- обертка создания http запросов - ASIHTTPRequest (https://github.com/pokeb/asi-http-request.git) !обязательно прочитатайте как она подключается http://allseeing-i.com/ASIHTTPRequest/Setup-instructions
- так же подключаем еще два файла (ASIHTTPRequest+YOAuthv1Request) из “ytoolkit/externals/asi-http-request additions/” добавляем стандартные библиотеки: CFNetwork, SystemConfiguration, MobileCoreServices, CoreGraphics, Security и libz.
Теперь нужно указать дополнительные флаги линкеру (это требует 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 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];
}
Исходный код: скачать