Яндекс OAuth авторизация в iOS

    Для вызовов API Яндекса приложению нужен токен. Получить его можно двумя способами. Первый способ самый простой — спрашиваем у пользоватея его логин и пароль и делаем POST-запрос на oauth.yandex.ru/token. Но есть пара проблем: пользователь может не захотеть доверить свой пароль от учетной записи стороннему приложению, да и сам Яндекс не рекомендует так делать. Второй немного более сложный в реализации способ и является предметом топика — OAuth авторизация.

    Регистрация приложения


    Процедура подробно описана на api.yandex.ru/oauth/doc/dg/tasks/register-client.xml.

    На этапе регистрации придумываем url-схему



    И запоминаем Id приложения



    Возможные варианты реализации


    Снова читаем документацию и понимаем что нам надо отобразить пользователю веб-страницу, с которой после успешной авторизации произойдет редирект на url со схемой которую мы указали на этапе регистрации.

    Тут возможны два подхода.
    1) Регистрируем приложение обработчиком указанной URL-схемы в системе. Открываем пользователю Safari с формой авторизации и ждем перезапуска приложения.
    Регистрация приложения обработчиком URL-схемы подробно описана здесь

    2) Показываем UIWebView и в его делегатских методах отлавливаем переход по нашей схеме.

    Второй подход мне кажется более простым, т.к. во-первых пользователь не покидает наше приложение, а во-вторых авторизация через Яндекс может быть едиственным способом входа в наше приложение.

    Пишем код


    Создаем тестовый проект в XCode.





    Добавляем в проект YandexOauthViewController.* (ссылка на исходный код в конце статьи).

    В YandexOauthViewController.h изменяем в следующих строках значения на ваши:

    #define URL_SCHEME @"iostestapp"
    #define CLIENT_ID @"6ef1c6dc6f134a2daa67cc905e5c1a3d"


    Во ViewController.h импортируем YandexOauthViewController.h и обявляем себя «реализатором» протокола YandexOauthViewControllerDelegate.

    #import <UIKit/UIKit.h>

    #import "YandexOauthViewController.h"

    @interface ViewController : UIViewController <YandexOauthViewControllerDelegate>

    @end


    В тестовом приложении будем авторизировать пользвателя при запуске. Для этого во ViewController.m изменяем метод ViewDidLoad:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
        
        YandexOauthViewController *cntrl = [[YandexOauthViewController alloc] init];
        cntrl.delegate = self;
        [self.navigationController presentModalViewController:cntrl animated:YES];
    }
    


    Какой еще self.navigationController, спросите вы и будете правы — навигейшен контроллера еще нет, поэтому добавляем его в AppDelegate.m:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        
        UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.viewController];
        
        self.window.rootViewController = nav;
        [self.window makeKeyAndVisible];
        return YES;
    }
    


    Запускаем приложение и видим так нужную нам форму авторизации.



    Кнопка слева (с крестиком) убирает форму авторизации с экрана, а правая кнопка возвращает пользователя на страницу авторизации. Дело в том, что в некоторых случаях Яндекс теряет цель нашего захода в авторизацию и и отображает профиль пользователя из которого нам токен уже не передадут.

    После ввода логина пароля и, в некоторых случаях, подтверждения постоянной авторизации на данном устройстве Яндекс перенаправляет нас по URL-схеме указанной прирегистрации приложения. Рассмотрим перехват этого перехода в файле YandexOauthViewController.m.

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
        //Получаем URL
        NSURL *url = [request URL];
        
        //Проверяем на соответствие пользовательской URL-схеме
        if ([url.scheme isEqualToString:URL_SCHEME])
        {
            //убираем индикатор сетевой активности
            UIApplication* app = [UIApplication sharedApplication];
            app.networkActivityIndicatorVisible = NO;
            
            //разбираем URL на отдельные элементы
            //наш токен будет в массиве arr под индексом 2
            NSArray *arr = [[url description] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"#=&"]];
            
            //говорим делегату об успешной авторизации и передаем токен
            if ([delegate respondsToSelector:@selector(yandexOauthViewController:succesfullLoginWithToken:)])
            {
                [delegate yandexOauthViewController:self succesfullLoginWithToken:[arr objectAtIndex:2]];
            }
            
            //запрещаем UIWebView открывать URL
            return NO;
        }
        
        //разрешаем UIWebView переход по URL
        return YES;
    }
    


    Осталось в ViewController.m реализовать протокол YandexOauthViewControllerDelegate.

    - (void)yandexOauthViewController:(YandexOauthViewController *)controller 
             succesfullLoginWithToken:(NSString *)token
    {
        [self.navigationController dismissModalViewControllerAnimated:YES];
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Авторизация удалась" 
                                                        message:[NSString stringWithFormat:@"Токен %@",token]                                                    
                                                       delegate:nil 
                                              cancelButtonTitle:@"Ok" 
                                              otherButtonTitles:nil];
        
        [alert show];
    }
    




    Спасибо всем кто дочитал до этого места.

    Ссылки


    1) Проект: github.com/eltiren/YandexOauth
    2) Документация по Яндекс OAuth: api.yandex.ru/oauth/doc/dg/concepts/About.xml
    Поделиться публикацией

    Комментарии 10

      +1
      Ну прямо день постов Яндекс (:
        +3
        И что же в Вашем случае заставит пользователя поверить, что пароль будет отправлен именно в Яндекс?
          –1
          Стандартный интерфейс авторизации яндекса. Особо недоверчивые могут также посерфить в этом окне.
            +1
            Согласен. Ничто не мешает сделать страницу с интерфейсом яндекса. Беда подобного способо авторизации
              0
              Большинство крупных отдают токен по oauth. Принцип в том что если вы залогинены на сайте, то он логин и пароль просить не будет… Хотя конкретно в этом случае не уверен что UIWebView вытащит куки сафари.
                +1
                UIWebView не вытащит куки Safari. Но есть некоторые плюшки — есть хранилище куки, для каждого приложения свое. Их можно получать, удалять, добавлять. Эти куки общие для всех UIWebView в приложении, а так же юзаются при NSURLConnection, если делаем запрос к HTTP.

                В данном случае можно сделать авторизацию на «большом» Яндексе, а потом кинуть на oauth и пароль не спросит. Хотя незнаю зачем так делать.
                  0
                  Для параноиков. Спасибо за уточнение, по поводу кук.
              0
              а разве в iOS нельзя сделать коллбэк из настоящего браузера (не UIWebView)?
                +1
                Можно,
                пример можно посмотреть в facebook iOS SDK,
                реализовывать oAauth авторизацию через встроенный UIWebView оправданно только на старых версиях iOs, где нет многозадачности
                  0
                  вот и я о том же — такой способ ведь гораздо безопаснее для пользователя

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое