Flickr API в Android App. Авторизация

в 16:32, , рубрики: Песочница, метки: , ,

Привет, читатели!

Хочу поделиться с вами небольшим опытом использования Flickr API в Android приложениях и рассказать об авторизации пользователя Flickr. Которую в дальнейшем можно будет использовать например для вывода списка альбомов и изображений.

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

Первым делом нам нужно получить API Key, приложения будем использовать не в коммерческих целях, для регистрации переходим по ссылке Create an App.

Flickr API в Android App. Авторизация - 1

Нас просят ввести «Название», «Цель» и «Соглашения с правами», отправляем наши данные и в результати получаем API Key и API Secret. Они нужны нам в дальнейшем для формирования запроса к серверу.

Flickr API в Android App. Авторизация - 2

После этого нам нужно редактировать некоторые данные, в этом же окне переходим на Edit auth flow for this app.

Flickr API в Android App. Авторизация - 3

Описания и логотип нам не интересны, вводить можете по желанию. В поле Callback URL нам обязательно нужно задать адрес обратного вызова, который мы будем использовать для возвращения к нашему Activity. В моем случае я задаю appforflickr://callback. В болке <intent-filter> это буде выглядеть следующим образом:

...
<data android:scheme="appforflickr" android:host="callback"/>
...

App Type — выбираем Web Application и Сохраняем изменения.

Далее переходим непосредственно к построения самого приложения.

В манифесте приложения добавляем «android.permission.INTERNET» и блок <intent-filter> в результате получаем:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.testflickrapi" >

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ui.activities.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>

                <data android:scheme="appforflickr" android:host="callback"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Создание ссылки для авторизации пользователя

Для авторизации пользователей в приложении мы будем запускать Activity с WebView. Но сначала сформируем адрес для входа. Шаблон выглядет следующим образом:

http://flickr.com/services/auth/?api_key=[api_key]&perms=[perms]&api_sig=[api_sig]

[api_key] — это наш ключ полученый при регистрации приложения. [perms] — уровень доступа к аккаунту, может принимать следующие значения:

  • read — разрешения на чтения личной информации
  • write — разрешения на добавления и редактирования фотографий и информации(включает в себя 'read')
  • delete — разрешения на удаления фотографий(включает в себя 'read' и 'write ')

[api_sig] — подпись, она включает в себя Secret полученый при регистрации приложения и список аргументов в алфавитном порядке, имя и значения.
В нашем случае API Key: 5744fadec815a7e8142d03901065c97b, API Secret: 8b2c12e80b67970b, права доступа write, подпись это строка из:

secret + 'api_key' + [api_key] + 'perms' + [perms]

, то есть мы имеем: 8b2c12e80b67970bapi_key5744fadec815a7e8142d03901065c97bpermswrite и теперь нужно зашифровать эту строку в MD5. Для этого используем следующий метод:

public static final String md5SumOfString(final String s) {
        try {
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
            digest.update(s.getBytes());
            byte messageDigest[] = digest.digest();

            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < messageDigest.length; i++)
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

и получем значения [api_sig].

В итоге адрес для авторизация пользователя будет выглядеть следующим образом:

http://www.flickr.com/services/auth/?api_key=9a0554259914a86fb9e7eb014e4e5d52&perms=write&api_sig=b8d7c1ae026d5f86f1f44944f5257f3

В onCreate() добавляем

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

, где url — это вышеуказанный адрес. После запуска приложения мы открываем веб-страницу, чтобы указать логин и пароль. Если введеные данные будут верны нас по Callback URL автоматически перенаправит на наше приложеня. К url добавляеться параметр frob из значениям, то есть в нашем случае это выглядит так:

appforflickr://callback?frob=72157650137623777-b09eae52121bf8ad-130818926

Frob нужен для получения Access token.
Добавим условия в onCreate(), чтобы получить frob:

Uri uri = getIntent().getData();
if (uri != null) {
    String frob = uri.getQueryParameter("frob");
} else 
	startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

После того обработки вызываем метод flickr.auth.getToken из API для получения token и nsid, которые понадобятся для дальнейших запросов, а так же username и fullname пользователя.

Для отправки запросов создадим class HttpRequest:

public class HttpRequest extends AsyncTask<String, String, String> {

    public static final String TAG = HttpRequest.class.getSimpleName();

    @Override
    protected void onPreExecute() {
        Log.d(TAG, "START");
    }

    @Override
    protected String doInBackground(String... params) {
        String result = "";
        try {
            String uri = params[0];
            HttpGet httpGet = new HttpGet(uri);
            HttpResponse response = HttpClientHelper.getHttpClient().execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inStream = entity.getContent();
                result = InputStreamConverter.convertStreamToString(inStream);
                inStream.close();
            }
            return result;
        } catch (IllegalStateException e) {
            return result;
        } catch (ClientProtocolException e) {
            return result;
        } catch (IOException e) {
            return result;
        }
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(TAG, "STOP");
    }
}

Class HttpClientHelper для получения HttpClient:

public class HttpClientHelper {

    private static HttpClient httpClient = null;
    private static final int REGISTRATION_TIMEOUT = 30 * 1000;
    private static final int WAIT_TIMEOUT = 30 * 1000;

    private HttpClientHelper() {}

    public static synchronized HttpClient getHttpClient() {
        if (httpClient == null) {
            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
            HttpProtocolParams.setUseExpectContinue(params, true);
            ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);
            HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
            HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
            SchemeRegistry schemeReg = new SchemeRegistry();
            schemeReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schemeReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
            ClientConnectionManager connectionMgr = new ThreadSafeClientConnManager(params, schemeReg);
            httpClient = new DefaultHttpClient(connectionMgr, params);
        }
        return httpClient;
    }
}

Class InputStreamConverter для конвертации InputStream в String:

public class InputStreamConverter {

    private InputStreamConverter() {}

    public static String convertStreamToString(InputStream inputStream) {
        BufferedReader reader = new BufferedReader(new InputStreamReader( inputStream));
        StringBuilder builder = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                builder.append(line + "n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return builder.toString();
    }
}

Адрес для получения token:

https://api.flickr.com/services/rest/?method=flickr.auth.getToken&api_key=9a0554259914a86fb9e7eb014e4e5d52&frob=72157650137623777-b09eae52121bf8ad-130818926&format=json&nojsoncallback=1&perms=write&api_sig=8fd09b55f670ec9a4ba07c076e520ae8

, чтобы ответ пришел в виде json мы добавили пераметры из значениями format=json и nojsoncallback=1

Вносим еще раз изминения в onCreate() для отправки запроса:

Uri uri = getIntent().getData();
if (uri != null) {
    String frob = uri.getQueryParameter("frob");
    String url = "..."; // Наш сформированый адрес для получения token
	
	String response = "";
	HttpRequest httpRequest = new HttpRequest(this);
	httpRequest.execute(url);
	try {
		response = httpRequest.get();
	} catch (InterruptedException | ExecutionException e) {
		e.printStackTrace();
	}
	
} else 
	startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

Далее полученый ответ:

{"auth":{"token":{"_content":"12134650097774510-014feda8303a4a64"},"perms":{"_content":"write"},"user":{"nsid":"230211065@N05","username":"user","fullname":"User Alex"}},"stat":"ok"}

можна розпарсить получить желанный token и nsid при помощи таких библиотек как gson или jackson это уже на любителя.

Надеюсь моя статья будет кому-то полезна.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js