Пользователь
–0,8
рейтинг
8 июля 2014 в 00:53

Разработка → Авторизация через Google в Android и проверка токена на сервере recovery mode

Недавно мне захотелось создать личный проект на андроиде, и основной вопрос был такой: как однозначно идентифицировать пользователя заставляя его делать как можно меньше телодвижений? Конечно же это аккаунт Google. Я пытался пробовать множество примеров в сети — однако API несколько раз обновилось за время своего существования, многие методы не работали, мои вопросы в Google+ по этому поводу либо были вообще никак не восприняты окружением, либо были вроде «Никогда такое не делал».
В этой статье я постараюсь как можно более просто для новичков (вроде меня) описать мой метод авторизации в Google на андроид, получения токена и проверке этого самого токена на сервере.

Небольшая подготовка


Для начала — у вас должны быть установлены Google Play Services в SDK. После их установки можно будет импортировать все необходимые библиотеки. Статья пишется с расчетом на Android Studio — он сам подсказывает, что необходимо импортировать.
У вас должно быть создано активити с кнопкой.
Чтобы было привычнее пользователю можете создать стандартную кнопку Google+ Sing-In
Выглядеть она будет вот так:
image
Просто добавьте в ваш Layout:
<com.google.android.gms.common.SignInButton
                android:id="@+id/sign_in_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>


Добавляем действие на кнопку


Пишем в нашем активити:
View btn = (View) findViewById(R.id.sign_in_button);
btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"},
                        false, null, null, null, null);
                startActivityForResult(intent, 123);

            }
        });

Собственно присвоим кнопке действие — вызов интенда выбора аккаунта. Если вы работаете в Android Studio он сам вам подскажет, какие библиотеки нужно импортировать, так что это подробно тут я расписывать не буду.
startActivityForResult(intent, 123); — задает код с которым произойдет возврат. 123 это код возврата, он может быть каким угодно. Это необходимо, когда вы делаете несколько интендов, и вам надо обработать их по разному.

Необходимые области доступа


Обьявите эти переменные в классе. Это необходимые нам области доступа. Первый написано в google: «Позволяет определить аутентифицированного пользователя. Для этого при вызове API необходимо указать me вместо идентификатора пользователя Google+. » Второе разрешение нам необходимо для получения личных данных пользователя (Имя, Фамилия, адрес G+ страницы, аватар), и последнее для получения E-mail. Я посчитал это важным, ведь это вполне неизменный идентификатор для записи в бд.
    private final static String G_PLUS_SCOPE =
            "oauth2:https://www.googleapis.com/auth/plus.me";
    private final static String USERINFO_SCOPE =
            "https://www.googleapis.com/auth/userinfo.profile";
    private final static String EMAIL_SCOPE =
            "https://www.googleapis.com/auth/userinfo.email";
    private final static String SCOPES = G_PLUS_SCOPE + " " + USERINFO_SCOPE + " " + EMAIL_SCOPE;


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


Изначально забыл этот пункт — исправляюсь.
Нам необходимо зайти на code.google.com/apis/console создать там проект, зайти в Credentials и создать новый Client ID для OAuth выбрав пункт Installed Application -> Android. Там нам необходимо ввести название нашего пакета и SHA1 сумму нашего ключа.
С этим у меня на самом деле было много проблем решил достаточно костыльным способом.
Нашел debug.keystore в %USERPROFILE%\.android\debug.keystore поместил в папку с проектом и прописал в build.grandle:

    signingConfigs {
        debug {
            storeFile file("debug.keystore")
        }

        myConfig {
            storeFile file("debug.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
    }

После чего нам нужно выполнить команду:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -v -list
Сам keytool можно найти в SDK. Из вывода копируем SHA1 в нужное поле.
Как я понимаю метод временный, и для нормальной работы надо создать нормальный ключ. Но для тестирования этого достаточно.

Код получения токена


protected void onActivityResult(final int requestCode, final int resultCode,
                                    final Intent data) {
        if (requestCode == 123 && resultCode == RESULT_OK) {
            final String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            AsyncTask<Void, Void, String> getToken = new AsyncTask<Void, Void, String>() {
                @Override
                protected String doInBackground(Void... params) {
                    try {
                        String token = GoogleAuthUtil.getToken(AcrivityName.this, accountName,
                                SCOPES);
                        return token;

                    } catch (UserRecoverableAuthException userAuthEx) {
                        startActivityForResult(userAuthEx.getIntent(), 123);
                    }  catch (IOException ioEx) {
                       Log.d(TAG, "IOException");
                    }  catch (GoogleAuthException fatalAuthEx)  {
                        Log.d(TAG, "Fatal Authorization Exception" + fatalAuthEx.getLocalizedMessage());
                    }
                    return token;
                }

                @Override
                protected void onPostExecute(String token) {
                    reg(token);
                }

            };
            getToken.execute(null, null, null);
        }
    }

Где 123 — ваш код, который вы указали ранее, где AcrivityName — название вашего актитивити. Грубо говоря — мы скармливаем функции получения токена необходимые разрешения и имя аккаунта. И заметьте — это все происходит в фоновом режиме, после чего полученный токен передается в написанную мною функцию reg. Она уже отправляет токен и все необходимые данные на сервер.
Так как разрабатываю недавно, с исключениями пока что беда, если есть предложение — напишите в личку или в комментарии.

Проверяем токен на сервере. (PHP)


Хочу обратить внимание, полученный нами токен имеет тип Online. И действует он лишь 10 минут. Для получения offline токена (чтобы дольше работать с ним с сервера) обратитесь к этой инструкции developers.google.com/accounts/docs/CrossClientAuth
$mToken = $_POST['plusToken'];
$userinfo = 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' . $mToken;
$json = file_get_contents($userinfo);
$userInfoArray = json_decode($json,true);
$googleEmail = $userInfoArray['email'];
$tokenUserId = $userInfoArray['user_id'];

Собственно скармливаем токен в googleapis и забираем полученный JSON ответ.

Заключение


Возможно код сырой и написан достаточно криво. Однако я целую неделю убил на поиск работающего решения. Решение это я нашел тут: android-developers.blogspot.ru/2012/09/google-play-services-and-oauth-identity.html, хотя оно и не полностью было работоспособно, в данной статье многое дополнено.
Предложения по улучшению статьи готов услышать в личке или в комментариях. Надеюсь сэкономлю некоторое время новичкам.
Карнаухов Олег @BupycNet
карма
2,0
рейтинг –0,8
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (16)

  • +2
    Мне, как новичку, то, что надо!
    • 0
      Если будут какие нибудь проблемы или вопросы спрашивайте, как раз вместе разберемся. Достаточно странно, сообщества по разработке под андроид есть, а вот взаимопомощи там достаточно мало, может кто знает какие нибудь активные сообщества?
      • 0
        Stackoverlow конечно же, Reddit, много чуваков из гугла и не только сидят в Google+, советую подписаться на них и отслеживать, вполне отвечают на вопросы, там и группы есть.
        Из ресурсов android-developers.blogspot.ru/ и androidweekly.net/
  • 0
    getToken.execute(null, null, null);
    В вашем случае параметры не нужны (вы это указали первым параметром дженерика AsyncTask) — в метод execute передаётся то, что потом попадёт в doInBackground
  • –3
    А ведь Google поддерживает и OpenID… Почему все используют OAuth только для того, чтобы потом запросить email пользователя?
  • –2
    Спасибо! Прикручу теперь и я!
    Но вот с SHA1 я так и не понял… буду гуглить.
  • –1
        android:paddingEnd="10px" 
    

    О Боже! Вы хоть прочитали базовые доки по расположению элементов UI?
    • –1
      Насчет этого я знаю, что будет выглядеть везде по разному из за этого. Но это скорее костыль для более удобного дебага. Пожалуй уберу это из статьи.
      Когда реализую основу своего приложения, тогда буду делать более адаптивный дизайн.
      • 0
        Просто забудьте про PX, используйте только DP для позиционирования и SP для размера шрифтов.
        • 0
          Не стоит всегда использовать sp, т.к. при изменении размера шрифта в настройках вся верстка может поехать. И используйте px для divider'ов если они должны быть 1px, т.к. если указать 1dp, то на ldpi устройствах 1dp округлится в 0px
          • 0
            Надо это учитывать при верстке. SP это обязательно нужно использовать.
  • 0
    То есть каждый раз пользователю придётся заново пройти авторизацию?
    • 0
      Почему же? Вообще я не понял до конца как оно работает, но у меня сейчас просто кнопка войти, так вот в первый раз оно спросило доступ и т.д. А все последующие нажатия — тишина. Просто получается online токен и с ним можно работать, никаких запросов нет. Думаю этот код можно в итоге просто в onCreate засунуть, главное на забыть то, что токен мы получаем в фоновом процессе.
      Как я понимаю, можно проверять есть ли доступ или нет, потом получать каждый раз токен если нам нужно работать с API. Ну и если есть доступ то просто не выводим кнопку, а что нибудь другое. В этой статье я описал именно как авторизироваться. получить токен и проверить его. Задача над проверкой авторизации при повторном входе, дальнейшее использовании авторизации и т.д. это уже придется гуглить самому. Как по мне главное сделать работоспособную основу, которая дает хоть результат.
      • 0
        Скрытый текст
        я не понял до конца как оно работает

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