- Метки урока:
- авторизация
- php
Аутентификация через Twitter
Привет, друзья! Да, да, да, наконец дошли руки до долгожданного урока, о котором просили многие из вас: реализации аутентификации через Twitter.
В прошлом году на нашем сайте был выложен целый ряд статей, направленных на раскрытие процессов аутентификации пользователей через различные социальные сети и сервисы. Тогда же поступило огромное множество просьб о том, чтобы мы показали как сделать то же самое через Twitter. Загвоздка заключалась в том, что данный сервис для аутентификации использовал и использует технологию oAuth1, в то время как все остальные перешли на oAuth2. Видя что Twitter не торопится переходить на новую технологию по сей день, я всё-таки решил сделать урок по текущему состоянию технологий.
Предыдущие уроки по этой теме:
- Аутентификация через ВКонтакте
- Аутентификация через Одноклассники
- Аутентификация через Mail.ru
- Аутентификация через Yandex
- Аутентификация через Google
- Аутентификация через Facebook
Заметка: некоторые из вас совершенно справедливо могут заметить, что Twitter частично поддерживает oAuth2, однако по данной схеме можно только осуществлять запросы к API, но не аутентифицировать пользователей.
Теперь, давайте приступим к делу и посмотрим на то, как всё-таки осуществить аутентификацию через Twitter. Готовьтесь! Нас ждёт множество шагов!
Шаг 1. Создание приложения
В первую очередь, вам необходимо создать новое Twitter приложение на сайте разработчиков (для логина можете использовать данные от вашего twitter аккаунта).
Для создания нового приложения нужно ввести следующие поля:
- Название приложения (Name)
- Описание (Description)
- Название вашего веб сайта (Website)
- Адрес куда будет отправлен пользователь после аутентификации (Callback URL)
В качестве адреса сайта и колбэка, я ввёл "http://twitterauth.loc/"
. Дело в том, что данное поле валидируется на правильность формата, поэтому значения типа "http://localhost/twitter-auth"
не подойдут. Хост для данного названия мы создадим на следующем шаге. Если вы хотите пробовать сразу на вашем существующем сайте, то введите его название. В дальнейшем все эти данные могут быть изменены во вкладке (settings).
После создания приложения для вас будут доступны следующие данные:
- Детальная информация о приложении.
- Специальные ключи приложения, секретные коды и так далее, которые вы сможете найти во вкладке API Keys.
- Права приложения, которые будут запрашиваться у пользователя. Все возможные варианты
Возможные варианты: “Читать твиты из вашей ленты”, “Видеть, кого вы читаете.”, "Читать новых людей.", "Обновлять ваш профиль.", "Публиковать твиты от вашего имени.", "Открыть доступ к вашим личным сообщениям." …
Шаг 2. Создание виртуального хоста
Для создания виртуального хоста на Windows, вам необходимо создать запись в файле “каталог_apache\conf\extra\httpd-vhosts.conf”:
<VirtualHost *:80> ServerName twitterauth.loc DocumentRoot "каталог_apache/htdocs/twitter-oauth" <Directory "каталог_apache/htdocs/twitter-oauth"> DirectoryIndex index.php AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>
Так же, необходимо внести запись в файл хостов Windows C:\Windows\System32\Drivers\etc\hosts:
127.0.0.1 twitterauth.loc
Перезапустите Apache. Зайдите по адресу http://twitterauth.loc/
. Если всё сделали правильно, то в результате вы должны увидеть содержимое каталога каталог_apache/htdocs/twitter-oauth
, где мы дальше будем работать.
В случае, если вы не хотите создавать свой хост, то можете попробовать урок на своём сайте.
Шаг 3. Определяем базовые настройки приложения
Теперь давайте приступим к написанию самого кода. Для начала сформируем список констант, куда запишем ключи полученные после регистрации Twitter-приложения, а так же адреса, которые будут использоваться для получения тех или иных данных.
define('CONSUMER_KEY', '3AMDpQZ9wjJboX3LpMFQ'); define('CONSUMER_SECRET', 'iKkE344c5dEcIJXjZqXkCyd7nckIXFvOC1GUMTZa0o'); // адрес получения токена запроса define('REQUEST_TOKEN_URL', 'https://api.twitter.com/oauth/request_token'); // адрес аутентификации define('AUTHORIZE_URL', 'https://api.twitter.com/oauth/authorize'); // адрес получения токена доступа define('ACCESS_TOKEN_URL', 'https://api.twitter.com/oauth/access_token'); // адрес API получения информации о пользователе define('ACCOUNT_DATA_URL', 'https://api.twitter.com/1.1/users/show.json'); // колбэк, адрес куда должен будет перенаправлен пользователь, после аутентификации define('CALLBACK_URL', 'http://twitterauth.loc/');
Шаг 4. Генерации подписи для запроса получения токена запроса (request token)
Теперь давайте расскажу что нам предстоит сделать: для начала необходимо создать ссылку, по которой кликнет пользователь для аутентификации. Её адрес будет состоять из набора параметров, сформированных особым образом и подписи запроса.
//определим разделитель, который отделять параметры друг от друга define('URL_SEPARATOR', '&');
Для создания подписи и адреса запроса нам понадобятся следующие параметры:
// хэш случайной строки $oauth_nonce = md5(uniqid(rand(), true)); // текущее время $oauth_timestamp = time();
Далее формируем набор параметров в строгой последовательности. Последовательность и кодирование определённых моментов действительно очень важна. В противном случае, запрос может не пройти:
// формируем набор параметров $params = array( 'oauth_callback=' . urlencode(CALLBACK_URL) . URL_SEPARATOR, 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_version=1.0' ); // склеиваем все параметры, применяя к каждому из них функцию urlencode $oauth_base_text = implode('', array_map('urlencode', $params)); // специальный ключ $key = CONSUMER_SECRET . URL_SEPARATOR; // формируем общий текст строки $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(REQUEST_TOKEN_URL) . URL_SEPARATOR . $oauth_base_text; // хэшируем с помощью алгоритма sha1 $oauth_signature = base64_encode(hash_hmac('sha1', $oauth_base_text, $key, true));
В результате у вас должно получиться значение типа: 5OeIu3Q8asBEweb9N3slIQ8L/jc=
Шаг 5. Формирование токена запроса (request token)
Теперь формируем строку параметров из тех же данных, которые использовались для формирования подписи запроса:
// готовим массив параметров $params = array( URL_SEPARATOR . 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_nonce=' . $oauth_nonce, 'oauth_signature=' . urlencode($oauth_signature), 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_version=1.0' ); // склеиваем параметры для формирования url $url = REQUEST_TOKEN_URL . '?oauth_callback=' . urlencode(CALLBACK_URL) . implode('&', $params); // Отправляем GET запрос по сформированному url $response = file_get_contents($url); // Парсим ответ parse_str($response, $response); // записываем ответ в переменные $oauth_token = $response['oauth_token']; $oauth_token_secret = $response['oauth_token_secret'];
В результате вы должны получить ответ вида:
oauth_token=udOL7svu5AdR49WAT5IfNB0cteo2OvNuZhHJbnqZLto&oauth_token_secret=jHlR6pcIL7dOlZmB7tGb8YC9TOyuWAeoDcuRFvVw&oauth_callback_confirmed=true
С помощью функции parse_str, преобразуем данную строку в массив и записываем в переменные $oauth_token и $oauth_token_secret. Если вы получили другой ответ, то значит отправили неверные данные.
Шаг 6. Формируем ссылку для аутентификации
$link = AUTHORIZE_URL . '?oauth_token=' . $oauth_token; echo '<a href="' . $link . '">Аутентификация через Twitter</a>';
Шаг 7. Формирование подписи для получения токена доступа
Теперь, когда у нас есть токен запроса и секрет токена запроса, самое время перейти к следующему шагу и получить, так называемый, токен доступа, с помощью которого получим доступ к данным пользователя. Но перед тем как получить сам токен доступа, сначала нужно сформировать подпись следующего запроса к twitter-у. Процесс предстоит тот же. Внимание! Весь следующий код будем писать в блоке:
if (!empty($_GET['oauth_token']) && !empty($_GET['oauth_verifier'])) { // далее всё пишем тут }
Итак, формируем подпись для получения токена доступа. Процедура та же, поэтому буду комментировать только новые моменты:
$oauth_nonce = md5(uniqid(rand(), true)); $oauth_timestamp = time(); // получаем oauth_token пришедший после перенаправления от Twitter-а $oauth_token = $_GET['oauth_token']; // получаем oauth_verifier пришедший после перенаправления от Twitter-а $oauth_verifier = $_GET['oauth_verifier']; $oauth_base_text = "GET&"; $oauth_base_text .= urlencode(ACCESS_TOKEN_URL)."&"; $params = array( 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_token=' . $oauth_token . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_verifier=' . $oauth_verifier . URL_SEPARATOR, 'oauth_version=1.0' ); $key = CONSUMER_SECRET . URL_SEPARATOR . $oauth_token_secret; $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(ACCESS_TOKEN_URL) . URL_SEPARATOR . implode('', array_map('urlencode', $params)); $oauth_signature = base64_encode(hash_hmac("sha1", $oauth_base_text, $key, true));
Шаг 8. Формируем строку параметров для получения токена доступа
Теперь, когда у нас есть подпись нового запроса, самое время сформировать саму строку этого запроса:
$params = array( 'oauth_nonce=' . $oauth_nonce, 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_token=' . urlencode($oauth_token), 'oauth_verifier=' . urlencode($oauth_verifier), 'oauth_signature=' . urlencode($oauth_signature), 'oauth_version=1.0' ); $url = ACCESS_TOKEN_URL . '?' . implode('&', $params); $response = file_get_contents($url); parse_str($response, $response);
Если вы сделали всё правильно, то в результате должны получить строку вида:
oauth_token=962149290-hpnbdORejotxrAuWTnCFI8gXhdp88Hv4J7KUH47s&oauth_token_secret=KlhUFBc7bsJvrsbMrIEa8XjiWfrA4iOeGlaFTdhcWS4V5&user_id=962149290&screen_name=stanislasprime
Шаг 9. Формируем подпись для запроса получения данных о пользователе
Приступаем к последней группе шагов. Осталось совсем немного. Теперь когда у нас есть токен доступа, можем получить данные о пользователе, который пытается аутентифицироваться. Для этого нужно отправить ещё один запрос, но перед этим, по уже сложившейся традиции, сформируем подпись данного запроса:
$oauth_nonce = md5(uniqid(rand(), true)); $oauth_timestamp = time(); $oauth_token = $response['oauth_token']; $oauth_token_secret = $response['oauth_token_secret']; $screen_name = $response['screen_name']; $params = array( 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_token=' . $oauth_token . URL_SEPARATOR, 'oauth_version=1.0' . URL_SEPARATOR, 'screen_name=' . $screen_name ); $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(ACCOUNT_DATA_URL) . URL_SEPARATOR . implode('', array_map('urlencode', $params)); $key = CONSUMER_SECRET . '&' . $oauth_token_secret; $signature = base64_encode(hash_hmac("sha1", $oauth_base_text, $key, true));
Шаг 10. Получаем данные о пользователе
Вот он, последний шаг, которые отделяет нас от пользовательских данных. Снова формируем набор параметров для формирования запроса:
$params = array( 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_nonce=' . $oauth_nonce, 'oauth_signature=' . urlencode($signature), 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_token=' . urlencode($oauth_token), 'oauth_version=1.0', 'screen_name=' . $screen_name ); $url = ACCOUNT_DATA_URL . '?' . implode(URL_SEPARATOR, $params); $response = file_get_contents($url); // преобразуем json в массив $user_data = json_decode($response);
Если вы сделали всё правильно, то в результате должны получить подобный ответ:
array (size=42) 'id' => int 962149290 'id_str' => string '962149290' (length=9) 'name' => string 'StanislaS Prime' (length=15) 'screen_name' => string 'stanislasprime' (length=14) 'location' => string 'Кишинёв-Одесса' (length=27) 'description' => string '' (length=0) 'url' => string 'http://t.co/q7Tswagq8q' (length=22) 'entities' => array (size=2) 'url' => array (size=1) 'urls' => array (size=1) ... 'description' => array (size=1) 'urls' => array (size=0) ... 'protected' => boolean false 'followers_count' => int 2 'friends_count' => int 7 'listed_count' => int 0 'created_at' => string 'Wed Nov 21 10:32:55 +0000 2012' (length=30) 'favourites_count' => int 0 'utc_offset' => int 10800 'time_zone' => string 'Kyiv' (length=4) 'geo_enabled' => boolean false 'verified' => boolean false 'statuses_count' => int 4 'lang' => string 'ru' (length=2) 'status' => array (size=22) 'created_at' => string 'Wed Mar 12 20:33:25 +0000 2014' (length=30) 'id' => float 4.4328406871875E+17 'id_str' => string '443784255087618230' (length=18) 'text' => string '' (length=230) 'source' => string 'web' (length=3) 'truncated' => boolean false 'in_reply_to_status_id' => null 'in_reply_to_status_id_str' => null 'in_reply_to_user_id' => null 'in_reply_to_user_id_str' => null 'in_reply_to_screen_name' => null 'geo' => null 'coordinates' => null 'place' => null 'contributors' => null 'retweet_count' => int 0 'favorite_count' => int 0 'entities' => array (size=5) 'hashtags' => array (size=0) ... 'symbols' => array (size=0) ... 'urls' => array (size=0) ... 'user_mentions' => array (size=0) ... 'media' => array (size=1) ... 'favorited' => boolean false 'retweeted' => boolean false 'possibly_sensitive' => boolean false 'lang' => string 'ru' (length=2) 'contributors_enabled' => boolean false 'is_translator' => boolean false 'is_translation_enabled' => boolean false 'profile_background_color' => string 'C0DEED' (length=6) 'profile_background_image_url' => string 'http://abs.twimg.com/images/themes/theme1/bg.png' (length=48) 'profile_background_image_url_https' => string 'https://abs.twimg.com/images/themes/theme1/bg.png' (length=49) 'profile_background_tile' => boolean false 'profile_image_url' => string 'http://pbs.twimg.com/profile_images/437485860859023360/voDNO_oY_normal.jpeg' (length=75) 'profile_image_url_https' => string 'https://pbs.twimg.com/profile_images/437485860859023360/voDNO_oY_normal.jpeg' (length=76) 'profile_link_color' => string '0084B4' (length=6) 'profile_sidebar_border_color' => string 'C0DEED' (length=6) 'profile_sidebar_fill_color' => string 'DDEEF6' (length=6) 'profile_text_color' => string '333333' (length=6) 'profile_use_background_image' => boolean true 'default_profile' => boolean true 'default_profile_image' => boolean false 'following' => boolean false 'follow_request_sent' => boolean false 'notifications' => boolean false 'suspended' => boolean false 'needs_phone_verification' => boolean false
Полный листинг
Привожу полный листинг кода. Не забудьте заменить значение констант на свои собственные.
// определяем изначальные конфигурационные данные define('CONSUMER_KEY', '3AMDpQZ9wjJboX3LpMFQ'); define('CONSUMER_SECRET', 'iKkE344c5dEcIJXjZqXkCyd7nckIXFvOC1GUMTZa0o'); define('REQUEST_TOKEN_URL', 'https://api.twitter.com/oauth/request_token'); define('AUTHORIZE_URL', 'https://api.twitter.com/oauth/authorize'); define('ACCESS_TOKEN_URL', 'https://api.twitter.com/oauth/access_token'); define('ACCOUNT_DATA_URL', 'https://api.twitter.com/1.1/users/show.json'); define('CALLBACK_URL', 'http://twitterauth.loc/'); // формируем подпись для получения токена доступа define('URL_SEPARATOR', '&'); $oauth_nonce = md5(uniqid(rand(), true)); $oauth_timestamp = time(); $params = array( 'oauth_callback=' . urlencode(CALLBACK_URL) . URL_SEPARATOR, 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_version=1.0' ); $oauth_base_text = implode('', array_map('urlencode', $params)); $key = CONSUMER_SECRET . URL_SEPARATOR; $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(REQUEST_TOKEN_URL) . URL_SEPARATOR . $oauth_base_text; $oauth_signature = base64_encode(hash_hmac('sha1', $oauth_base_text, $key, true)); // получаем токен запроса $params = array( URL_SEPARATOR . 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_nonce=' . $oauth_nonce, 'oauth_signature=' . urlencode($oauth_signature), 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_version=1.0' ); $url = REQUEST_TOKEN_URL . '?oauth_callback=' . urlencode(CALLBACK_URL) . implode('&', $params); $response = file_get_contents($url); parse_str($response, $response); $oauth_token = $response['oauth_token']; $oauth_token_secret = $response['oauth_token_secret']; // генерируем ссылку аутентификации $link = AUTHORIZE_URL . '?oauth_token=' . $oauth_token; echo '<a href="' . $link . '">Аутентификация через Twitter</a>'; if (!empty($_GET['oauth_token']) && !empty($_GET['oauth_verifier'])) { // готовим подпись для получения токена доступа $oauth_nonce = md5(uniqid(rand(), true)); $oauth_timestamp = time(); $oauth_token = $_GET['oauth_token']; $oauth_verifier = $_GET['oauth_verifier']; $oauth_base_text = "GET&"; $oauth_base_text .= urlencode(ACCESS_TOKEN_URL)."&"; $params = array( 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_token=' . $oauth_token . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_verifier=' . $oauth_verifier . URL_SEPARATOR, 'oauth_version=1.0' ); $key = CONSUMER_SECRET . URL_SEPARATOR . $oauth_token_secret; $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(ACCESS_TOKEN_URL) . URL_SEPARATOR . implode('', array_map('urlencode', $params)); $oauth_signature = base64_encode(hash_hmac("sha1", $oauth_base_text, $key, true)); // получаем токен доступа $params = array( 'oauth_nonce=' . $oauth_nonce, 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_token=' . urlencode($oauth_token), 'oauth_verifier=' . urlencode($oauth_verifier), 'oauth_signature=' . urlencode($oauth_signature), 'oauth_version=1.0' ); $url = ACCESS_TOKEN_URL . '?' . implode('&', $params); $response = file_get_contents($url); parse_str($response, $response); // формируем подпись для следующего запроса $oauth_nonce = md5(uniqid(rand(), true)); $oauth_timestamp = time(); $oauth_token = $response['oauth_token']; $oauth_token_secret = $response['oauth_token_secret']; $screen_name = $response['screen_name']; $params = array( 'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR, 'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR, 'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR, 'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR, 'oauth_token=' . $oauth_token . URL_SEPARATOR, 'oauth_version=1.0' . URL_SEPARATOR, 'screen_name=' . $screen_name ); $oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(ACCOUNT_DATA_URL) . URL_SEPARATOR . implode('', array_map('urlencode', $params)); $key = CONSUMER_SECRET . '&' . $oauth_token_secret; $signature = base64_encode(hash_hmac("sha1", $oauth_base_text, $key, true)); // получаем данные о пользователе $params = array( 'oauth_consumer_key=' . CONSUMER_KEY, 'oauth_nonce=' . $oauth_nonce, 'oauth_signature=' . urlencode($signature), 'oauth_signature_method=HMAC-SHA1', 'oauth_timestamp=' . $oauth_timestamp, 'oauth_token=' . urlencode($oauth_token), 'oauth_version=1.0', 'screen_name=' . $screen_name ); $url = ACCOUNT_DATA_URL . '?' . implode(URL_SEPARATOR, $params); $response = file_get_contents($url); $user_data = json_decode($response, true); var_dump($user_data); }
Итог
Фуууух, вот это мы дали жару! Вот такой вот непростой процесс создания аутентификации через Twitter. Ждём ваших отзывов. В случае если у вас что-то не выходит, 100 раз убедитесь, что все изначальные данные верны и хост настроен верно.
Так же совет. В процессе разработки не нажимайте F5 для обновления страницы, т.к. полученные токены могут устаревать и полезет куча ошибок. Если вам нужно пере-аутентифицироваться, то нажимайте на соответствующую ссылку.
Спасибо за внимание!
Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: www.ruseller.com
Автор: Станислав Протасевич
Урок создан: 13 Апреля 2014
Просмотров: 29269
Правила перепечатки
5 последних уроков рубрики "PHP"
-
Фильтрация данных с помощью zend-filter
Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.
-
Контекстное экранирование с помощью zend-escaper
Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.
-
Подключение Zend модулей к Expressive
Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.
-
Совет: отправка информации в Google Analytics через API
Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.
-
Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.