- Аутентификация через OAuth2
- Запрос Auth Token
- Подключение к онлайн-сервисам
- Авторизация через Google в Android и проверка токена на сервере
- Небольшая подготовка
- Добавляем действие на кнопку
- Необходимые области доступа
- Регистрация нашего приложения.
- Код получения токена
- Проверяем токен на сервере. (PHP)
- OAuth 2 on Android (Principles using Google Apis)
- OAuth 2.0 on Android
- OAuth 2 basics principles
- Google Console Registration
- Create the project
- Activate your API
- Create your OAuth client ID
- Back to our application. First step: Talk with the authorization server
- key point:
- Launching the browser with the right information for the authorization server
- Redirect_URI
- Launching the browser with the right parameters and URL
- Listening for the Authorization server response
- Second step: Ask for the OAuth token
- Using retrofit
- Define your Interface
- Instantiate your interface using Retrofit
- Use your retorfit webServer
- Last step: Use the Apis services of the server using your token
- Retrofit Interface
- Instantiate your interface using Retrofit
- Make your call
- Important details
- Managing the token expiration
- Storing the Token
- Application inner workflow
- Next step: AccountManager
Аутентификация через OAuth2
Чтобы получить доступ к некоторым онлайн-сервисам, пользователям нужно пройти аутентификацию. Обычно он вводит свой логин и пароль в браузере. Если вы создаёте своё приложение, которое будет подключаться к такому сервису, то не только пользователь должен пройти аутентификацию для доступа к сервису в вашем приложении, но и приложение должно быть авторизовано для выполнения действий от имени пользователя.
На данный момент стандартным протоколом для аутентификация является OAuth2 (Open Authorization). OAuth2 обеспечивает единственное значение, называемое токен авторизации (Auth Token), который представляет как пользователя, так и авторизованное приложения, которое будет действовать от имени пользователя.
Протокол используют Twitter, Google, Flickr, Digg, Yahoo и многие другие сервисы.
Необходимо понимать разницу между терминами аутентификация (authentication) и авторизация (authorization).
Аутентификация — вы посещаете режимное предприятие и показываете своё удостоверение. Охранник смотрит и принимает решение: удостоверение настоящее? печать на месте? фотка совпадает? Опытный охранник может узнать вас в лицо и пропустить и так. Аутентификация может быть простой, а может быть и сложной.
На сайтах обычно аутентификация происходит по схеме логин/пароль, заставляя пользователя вводить данные и проверяя их на сервере.
Авторизация наступает после успешной аутентификации. Даже если вы показали настоящее удостоверение, у вас может быть запрет на посещение отдельных этажей, комнат, серверной и т.д. Или вы не можете пройти в здание по выходным.
Авторизация определяет ограничения на доступные действия. Используя OAuth, мы задаём границы доступа пользователя. Например, пользователь может читать личные сообщения, а босс может просматривать переписку любого сотрудника. Причём, открытая аутентификация означает, что мы сами не занимаемся проверкой логина и пароля, а только получаем готовую информацию. Иными словами, организация заключила договор с охранным предприятием, который и поставляет охранников и занимается системой охраны.
Использование OAuth2 подходит для:
- Получения разрешения от пользователя для доступа к онлайн-службе с помощью своей учетной записи.
- Аутентификация на онлайн-сервисе от имени пользователя.
- Обработка ошибок аутентификации.
Чтобы начать использовать OAuth2, вы должны знать:
- URL сервиса, к которому вы хотите получить доступ.
- Рамки аутентификации (auth scope), которые являются строкой, определяющей конкретный тип доступа, запрашиваемый вашим приложением. Например, запрос доступа только для чтения к Google Tasks – это View your tasks, в то время как доступ для чтения и записи к Google Tasks – это Manage Your Tasks.
- Идентификатор клиента (client id) и «секрет клиента» (client secret) – это строки, которые идентифицируют ваше приложение на сервисе. Вы должны получить эти строки непосредственно у владельца сервиса. Google имеет систему самообслуживания для получения идентификаторов клиента и секретов. Статья Getting Started with the Tasks API and OAuth 2.0 on Android объясняет, как использовать эту систему, чтобы получить эти значения для использования c Google Tasks API.
Запрос Auth Token
Теперь вы готовы запрашивать токен авторизации. Это многоступенчатый процесс.
Для получения токена авторизации необходимо сначала запросить права на использование ACCOUNT_MANAGER в манифесте. Не забываем про разрешение на интернет.
Имея необходимые полномочия, вы можете вызвать AccountManager.getAuthToken() для получения токена. Большинство методов AccountManager – асинхронные. Вам придётся реализовать её в виде серии обратных вызовов, например:
В этом примере класс OnTokenAcquired расширяет AccountManagerCallback. AccountManager вызывает run() в OnTokenAcquired с AccountManagerFuture, содержащим Bundle. Если вызов успешен, то токен будет внутри Bundle.
Вы можете получить токен из Bundle:
Если все пойдёт хорошо, то Bundle будет содержать допустимый токен в ключе KEY_AUTHTOKEN. Но не всегда все идёт так как запланированно.
Ваш первый запрос токена авторизации может завершиться неудачей по нескольким причинам:
- Ошибка в устройстве или сети вызвала сбой AccountManager.
- Пользователь решил не предоставлять вашему приложению доступ к аккаунту.
- Сохраненных полномочий аккаунта не хватает для получения доступа к аккаунту.
- Кэшированный токен авторизации истек.
Приложения могут обрабатывать первые два случая, показывая сообщение об ошибке пользователю. Если сеть не работает или пользователь решил не предоставлять доступ, то ваше приложение ничего не может с этим поделать. Последние два случая немного сложнее, потому что хорошо оптимизированные приложения должны обрабатывать эти неудачи автоматически.
Третий случай неудачи, имеющий недостаточные полномочия, передается через Bundle, который вы получаете в вашем AccountManagerCallback (OnTokenAcquired из предыдущего примера). Если Bundle включает Intent в ключе KEY_INTENT, то аутентификатор говорит вам, что ему необходимо прямое взаимодействие с пользователем, прежде чем он может дать вам действительный токен.
У аутентификатора может быть много причин для возврата Intent. Это может быть первый вход пользователя в эту учетную запись. Возможно время учетной записи пользователя истекло и требуется повторный вход в систему или сохраненные полномочия неверны. Может быть аккаунт требует двухфакторной аутентификации либо требуется включение камеры для сканирования сетчатки. В действительности причина не имеет значения. Если вы хотите действительный токен, вы должны обратиться к Intent, чтобы получить его.
Обратите внимание, что пример использует startActivityForResult(), и вы можете перехватить результат Intent в методе onActivityResult() в вашей активности. Если вы не станете перехватывать результат ответа Intent аутентификатора, невозможно будет определить прошёл ли пользователь проверку подлинности или нет. Если результат RESULT_OK, то аутентификатор обновил сохранённые полномочия, чтобы они были достаточны для доступа который вы запросили, далее вы должны вызвать AccountManager.getAuthToken() снова и запросить новый токен аутентификации.
Последний случай, когда токен истёк, на самом деле не ошибка AccountManager. Единственный способ выяснить действительно ли токен истек – это связаться с сервером, что было бы расточительным и дорогим со стороны AccountManager постоянно выходить в интернет и проверять состояние всех своих токенов. Так что эта неудача может быть обнаружено только когда приложение пытается использовать токен аутентификации для доступа к веб сервису.
Подключение к онлайн-сервисам
Пример ниже показывает, как подключиться к серверу Google. Так как Google использует стандарт протокола OAuth2 для проверки подлинности запросов, методы, обсуждаемые здесь широко применимы. Имейте в виду, что каждый сервер отличается. Вам может понадобиться внести небольшие изменения в этот пример для учета вашей конкретной ситуации.
Google API требует предоставления четырех значений с каждым запросом: API key, client ID, client secret, и auth key. Первые три получаются на сайте Google API Console. Последнее значение вы получаете вызвав AccountManager.getAuthToken(). Вы передаете их на сервер Google в качестве части HTTP-запроса.
Если запрос возвращает HTTP-ошибку 401, то ваш токен был отклонен. Самая распространённая причина этого – истечение токена. Исправить это просто: вызовите AccountManager.invalidateAuthToken() и повторите запрос токена еще раз.
Так как истечение токена является обычным явлением и исправление этой ситуации достаточно легкое, многие приложения просто предполагают истечение токена ещё до того как станет известно об этом. Если обновление токена дешёвая операция для вашего сервера, вы можете вызывать AccountManager.invalidateAuthToken() перед первым вызовом AccountManager.getAuthToken() и избавить себя от необходимость запрашивать токен аутентификации два раза.
В будущем мы рассмотрим практические примеры для OAuth.
Источник
Авторизация через Google в Android и проверка токена на сервере
Недавно мне захотелось создать личный проект на андроиде, и основной вопрос был такой: как однозначно идентифицировать пользователя заставляя его делать как можно меньше телодвижений? Конечно же это аккаунт Google. Я пытался пробовать множество примеров в сети — однако API несколько раз обновилось за время своего существования, многие методы не работали, мои вопросы в Google+ по этому поводу либо были вообще никак не восприняты окружением, либо были вроде «Никогда такое не делал».
В этой статье я постараюсь как можно более просто для новичков (вроде меня) описать мой метод авторизации в Google на андроид, получения токена и проверке этого самого токена на сервере.
Небольшая подготовка
Для начала — у вас должны быть установлены Google Play Services в SDK. После их установки можно будет импортировать все необходимые библиотеки. Статья пишется с расчетом на Android Studio — он сам подсказывает, что необходимо импортировать.
У вас должно быть создано активити с кнопкой.
Чтобы было привычнее пользователю можете создать стандартную кнопку Google+ Sing-In
Выглядеть она будет вот так:
Просто добавьте в ваш Layout:
Добавляем действие на кнопку
Пишем в нашем активити:
Собственно присвоим кнопке действие — вызов интенда выбора аккаунта. Если вы работаете в Android Studio он сам вам подскажет, какие библиотеки нужно импортировать, так что это подробно тут я расписывать не буду.
startActivityForResult(intent, 123); — задает код с которым произойдет возврат. 123 это код возврата, он может быть каким угодно. Это необходимо, когда вы делаете несколько интендов, и вам надо обработать их по разному.
Необходимые области доступа
Обьявите эти переменные в классе. Это необходимые нам области доступа. Первый написано в google: «Позволяет определить аутентифицированного пользователя. Для этого при вызове API необходимо указать me вместо идентификатора пользователя Google+. » Второе разрешение нам необходимо для получения личных данных пользователя (Имя, Фамилия, адрес G+ страницы, аватар), и последнее для получения E-mail. Я посчитал это важным, ведь это вполне неизменный идентификатор для записи в бд.
Регистрация нашего приложения.
Изначально забыл этот пункт — исправляюсь.
Нам необходимо зайти на code.google.com/apis/console создать там проект, зайти в Credentials и создать новый Client ID для OAuth выбрав пункт Installed Application -> Android. Там нам необходимо ввести название нашего пакета и SHA1 сумму нашего ключа.
С этим у меня на самом деле было много проблем решил достаточно костыльным способом.
Нашел debug.keystore в %USERPROFILE%\.android\debug.keystore поместил в папку с проектом и прописал в build.grandle:
После чего нам нужно выполнить команду:
keytool -exportcert -alias androiddebugkey -keystore
/.android/debug.keystore -v -list
Сам keytool можно найти в SDK. Из вывода копируем SHA1 в нужное поле.
Как я понимаю метод временный, и для нормальной работы надо создать нормальный ключ. Но для тестирования этого достаточно.
Код получения токена
Где 123 — ваш код, который вы указали ранее, где AcrivityName — название вашего актитивити. Грубо говоря — мы скармливаем функции получения токена необходимые разрешения и имя аккаунта. И заметьте — это все происходит в фоновом режиме, после чего полученный токен передается в написанную мною функцию reg. Она уже отправляет токен и все необходимые данные на сервер.
Так как разрабатываю недавно, с исключениями пока что беда, если есть предложение — напишите в личку или в комментарии.
Проверяем токен на сервере. (PHP)
Хочу обратить внимание, полученный нами токен имеет тип Online. И действует он лишь 10 минут. Для получения offline токена (чтобы дольше работать с ним с сервера) обратитесь к этой инструкции developers.google.com/accounts/docs/CrossClientAuth
Собственно скармливаем токен в googleapis и забираем полученный JSON ответ.
Источник
OAuth 2 on Android (Principles using Google Apis)
android2ee (Seguy Mathias)
Jan 9, 2017 · 14 min read
Mathias thinks you, as Android developer, can be interested by the following article : Rx Android everywhere… why, but why ?
OAuth 2.0 on Android
This document explain how to set OAuth2.0 between an Android native application and a GoogleApi (GDrive). It aims to show in a general way how to implement OAuth on Android.
We only focuse on establishing a OAuth communication between our application and GDrive, we don’t introduce the Account (Android AccountManager) to store this stoken, not yet a next document will explain that and what are the goals of using the Account.
The co d e can be found here :
If you want to use it, you need to register yourself on the google console (I means at least you the SHA-1 of your Debug key).
Warning: If you want to use GDrive Api on Android, just don’t do that, use the ApiClient of the GooglePlay services. It’s less less work. Here is an exemple to use OAuth, not to access to GDrive.
OAuth 2 basics principles
This is a 3 steps authentication,
- you register your application in the google console and then receive your clientID
- then you talk to an authorization server with your clientID, which returns you a code,
- using this code, you then can talk to the api server and ask for the token.
When you have your token, you can use it to access protected data, on google drive, using the OAuth protocol.
We’ll see how to make each of this steps.
Google Console Registration
It’s always the case, for all OAuth communication, you need to register your application on the server you want to use.
Create the project
Activate your API
You create a new project and you choose which Api you want to access :
In our exemple, we choose GDrive api. So you click on it and activate it (the button will change itself into Desactiver).
Create your OAuth client ID
Then you go, using the left tabs, to the identification part:
And you can create your ID (by clicking on create id):
You have several choices, choose “ID Client OAuth”. (the console asks you to give a name to your project, give it).
Then you are in front the following form:
You choose Android and you need to give the following information:
- the root package of your application
- and the SHA-1 of your signature key
Both are obvious…
Perhaps the SHA-1 not. KeyTool is a tool of your Java instalation, you can find it in your Java sdk. So go in your Java/sdk/bin and run the command line and then run the command ahead (keytool gnagnagna).
When you have done that you have the ClientId to use when communicating with the authorization server.
Back to our application. First step: Talk with the authorization server
We have our ClienttId, we can now communicate with the Authorization server… but in fact not, not directly.
We need to use a browser to talk to the authorization server (because browser are trusted application and yours is not). So we will launch a browser with the url (of the auth server) and the parameter needed for the authorization server and wait for the answer…
But how the answer will reach back your application ? OAuth use a concept called redirect_url. When the authorization server wants to answer, it will use this redirect_uri to send you the information…
But wait, I am an Android application, I am not a server, I can not be reached using a redirect_url.
To resolve that, some OAuth services, like those of the google apis, allow you to give them a redirect_url which is in fact, not and url but a uri/a schema. The code sent back to the browser will them build an Intent, with the schema you gave to the server, and launch this Intent in the Android system. So you just have to register a Service or an Activity to be activated when this specific Intent is launched by the system. And it’s done.
The next paragraphs will explain how to do that in the details.
key point:
The authorization server must allowed schema as redirect_url. If it does not, you’re screwed and you need to define your own server just to handle the authorization server’s answer and to make a push from your server to the application. So if you build your own authorization server, please allow schema .
Launching the browser with the right information for the authorization server
First, we need to know, what are the information expected by the authorization server.
Most of the time we have the following elements to send to it:
- Your Client_ID (it needs to know who is talking to)
- Your redirect_uri (how can the server can send you back the information)
- Your scope (what do you want to do)
- Your response type (what format do you expect for the answer).
For native application, at least for GoogleApis, your response type is always equals to “code”. The server will send you a code you’ll use when asking for the token.
Your scope depends on which Apis you use and what you want to do, in my exemple, I use https://www.googleapis.com/auth/drive which is the “I can do anything on your GDrive”.
You have your Client_Id from the registration step.
Now, we just have to take a look at that Redirect_URI parameter.
Redirect_URI
Most of the time, an https url is expected. But with the revolution of the smartphones and Android specifically, some actors of the IT world make evolve the specifications and allow URI (based on schema).
So they allow us to give an URI. How does it works:
If I say, my schema (==URI) is
Then an Intent will be launched by the system with action =”View” and schema=”com.android2ee.oath.githubsample”.
To listen for that Intent and launch my treatment, I just need to add an Activity or a Service that wakes up each time the Intent is sent by the system. To do that, every things happen in your manifest.xml file in your application. You just have to declare it like that:
Launching the browser with the right parameters and URL
On Android it’s obvious how to launch the native browser and ask it to display a specific url, you just need to send an Intent in the system:
First, build your URL:
HttpUrl authorizeUrl = HttpUrl.parse(«https://accounts.google.com/o/oauth2/v2/auth») //
.newBuilder() //
.addQueryParameter(«client_id», CLIENT_ID)
.addQueryParameter(«scope», API_SCOPE)
.addQueryParameter(«redirect_uri», REDIRECT_URI)
.addQueryParameter(«response_type», CODE)
.build();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(String.valueOf(authorizeUrl.url())));
startActivity(i);
Remark: You use an Https connection.
Listening for the Authorization server response
So, in your manifest, you declared an Activity (or a Service) to be woke up when the system send an Intent with the schema you gave as redirect_uri.
When the server reply to the browser, it just ask the browser to launch an Intent with the same schema. So it immediately wakes up your activity.
Now, you just have to analyse the response in your Activity. So in your onCreate :
You find the Intent that wakes you up. You look in its bundle, if it has the good schema. If it does, it’s our use case, we analyse it, we retrieve the code and the error. One of those is always null.
If you have a code, you can go to the next step which is ask for the token. If you have an error, that means, your user doesn’t want to grant you those rights or a problem occurs when connecting to the server, or… but you are screwed, you can’t do anything.
Second step: Ask for the OAuth token
This step is straight, you just have to send a request to the server api with your code (the one you just received), your clientId (the one you had at your registration), your redirectUri (the same as before) and your expected grantType:
The grantType is “authorization_code” because you use a code.
How can we do that on Android in a proper way : we use Retrofit.
Using retrofit
Using Retrofit is the clever way to handle your http communication, so we will use it.
Define your Interface
Here we just define that the method requestTokenForm is
- making a post to rootURL/oauth2/v4/token (rootUrl is not defined yet)
- returning a Call that encapsulated an OAuthToken (a specific class you write yourself that represents in an Object way the server’s response)
- filled with the parameters code, clientId, redirectUri and GrantType and those parameters are wrap as a Form within your request.
Where the class OAuthToken is :
Instantiate your interface using Retrofit
Here, we simply, ask to Retrofit to build a instance of the interface with all the elements needed to make it works:
So we just build the Retrofit object by giving him :
- an Http client
- a converter to automaticly convert JSon into Object
- the base URL for our requests
And using this retrofit object, we create our “webServer” by insanciating our interface into a real class that can do the job.
Use your retorfit webServer
Now, we just need to use it:
So using our webServer, we create our Call using the right parameters and we make the request (using enqueue).
The call is done in an asynchronous way and in the onResponse method we retrieve our OAuth object. We store it to use latter.
Now we have our token . we are allowed to use the services provides by the api server.
Last step: Use the Apis services of the server using your token
Now, when we want to call an end-point of the api (server side), we just need to add in our header our token.
Retrofit Interface
To do that, we, once again use RetroFit. So in our interface, we add the different rest calls we want to make:
We define for that a method called listFiles which:
- makes a Get on drive/v3/files
- returns a Call that encapsulate GDriveFiles (a class you write yourself that is the representation of the JSon object send by the server)
Instantiate your interface using Retrofit
Again, it’s simple:
The trick here is that you don’t use a simple Http client, no, you use one that automatically set the header of your request as expected:
You added a oAuthInterceptor, which is in fact a simple class:
This class intercepts each request sent and adds “”Authorization”,accessTokenType+” “ + accessToken” to the header of the request.
Simple, straight, easy.
Remark that if the token is empty, we relaunch the LoginActivity which is charge of managing the token (the whole authentication process is handle by it).
Make your call
Once again, it’s really simple:
You instantiate your interface using your RetrofitBuilder and take care to use the OAuthClient (not the simple one).
You instantiate your Call, you do it using enqueue and in the call back you have your server’s response.
Important details
Managing the token expiration
Your token will expired, so you need to check it’s expiration date and to renew it.
To do that,I made my OAuthToken object smart, he has two method save and restore, where:
When we save it, we calculate the expirationDate in millis.
When we restore it, we look at this expiration date, if the date is past, we return set the field token to null.
When the login activity (first activity launch of your application) wants to know if we had a token, there is two cases.
- OAuthToken is null => we need to run from the first step
- OAuthToken !=null but token == null => we need to refresh the token
- OAuthToken =!= null and token !null => the token is still good, we can use it
So when we detect OAuthToken != null and token ==null, we launch the refresh process, which is quiet simple. We just need to send again to the apis server the refreshToken (we received with the token), our clientId and the grantType (which is still “authorization_code”).
Ok, to do that, guess what, we still use retrofit:
Same as before, we instantiate this interface using Retrofit, and then we use it like that:
And it’s done, you have refereshed your token.
Storing the Token
To store the token, I use the SharedPreferences object:
The point here, which is a security breach, is I don’t encrypt the token when storing it.
Application inner workflow
A big question for Android developers is how I shape my code to implement properly this workflow.
I think, the good practice is to have a LoginActivity which here to handle all the OAuth process describes in this document. This LoginActivity is the start activity. It checks the state of the token, fix it if needed and then launch your mainActivity.
This way, you don’t have piece of OAuth code all around your appluication. This is a really important element to take into account.
Next step: AccountManager
How long your token should last ?
This question is simple but the answer is not.
To have a good user experience we perhaps need to make calls in background to retrieve information and display them to the user when he launchs the application (even if he has no connection at that moment). So for us, token should not die. For information, it’s the way Google, CaptainTrain, Twitter, Facebook… are doing.
If we want to be able to do such a stuff, which leads to great user experience, we need to store our token in an system object called Account, where you can store in a secure way your credentials.
Источник