OAuth авторизация через Twitter

OAuth авторизация через Twitter

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

Подготовка.

Регистрация в сервисе - дело простейшее.

Далее создание приложения. Никаких прав разработчика запрашивать не нужно, приложение можно сразу создавать по этой ссылке. Пункт "Callback URL" заполнять не обязательно - его можно передавать непосредственно в запросах. Из самого приложения самыми важными для работы данными являются Consumer Key (API Key) и Consumer Secret (API Secret), они находятся во вкладке "Keys and Access Tokens".

На apps.twitter.com можно увидеть список имеющихся приложений.

Процесс.

Основные определения были описаны в начале этой статьи, почитайте вступление, если еще не читали. Про redirect() было сказано здесь. Получившийся класс можно скачать ниже из раздела "дополнительно".

class OAuthTwitter < const CONSUMER_KEY = 'consumer_key' ; const CONSUMER_SECRET = 'consumer_secret' ; const URL_CALLBACK = 'http://example.com/oauth/twitter.php' ; //URL, на который произойдет перенаправление после авторизации >

Перенаправление на авторизацию здесь сложнее, чем у большинства, - сначала необходимо запросить токен и лишь потом отправить пользователя на подтверждение доступа. Все запросы токенов дополнительно требуют захэшированных параметров, этот хэш отправляется в поле oauth_signature. Само хэширование вынесено в метод encode. Параметр oauth_nonce - это уникальный маркер запроса, служит для защиты от повторных запросов с тем же набором параметров. Также внимания заслуживает параметр oauth_timestamp - если передаваемое в нём время сильно отличается от актуального, то запрос будет отклонён Твиттером, так что проверьте время сервера. Полученное значение oauth_token_secret позже понадобится при запросе токена доступа (это уже другой токен), потому оно записывается в $_SESSION.

class OAuthTwitter < const URL_REQUEST_TOKEN = 'https://api.twitter.com/oauth/request_token' ; const URL_AUTHORIZE = 'https://api.twitter.com/oauth/authorize' ; public static function goToAuth ( ) < $oauth_nonce = md5 ( uniqid ( rand ( ) , true ) ) ; $oauth_timestamp = time ( ) ;

$oauth_base_text = "GET&" . urlencode ( self :: URL_REQUEST_TOKEN ) . "&" . urlencode ( "oauth_callback color:#393">. urlencode ( self :: URL_CALLBACK ) . "&" . "oauth_consumer_key color:#393">. self :: CONSUMER_KEY . "&" . "oauth_nonce color:#393">. $oauth_nonce . "&" . "oauth_signature_method=HMAC-SHA1&" . "oauth_timestamp color:#393">. $oauth_timestamp . "&" . "oauth_version=1.0" ) ;

$key = self :: CONSUMER_SECRET . "&" ; $oauth_signature = self :: encode ( $oauth_base_text , $key ) ;

$url = self :: URL_REQUEST_TOKEN . '?oauth_callback=' . urlencode ( self :: URL_CALLBACK ) . '&oauth_consumer_key=' . self :: CONSUMER_KEY . '&oauth_nonce=' . $oauth_nonce . '&oauth_signature=' . urlencode ( $oauth_signature ) . '&oauth_signature_method=HMAC-SHA1' . '&oauth_timestamp=' . $oauth_timestamp . '&oauth_version=1.0' ;

if ( ! ( $response = @ file_get_contents ( $url ) ) ) < return false ; > parse_str ( $response , $result ) ;

if ( empty ( $result [ 'oauth_token_secret' ] ) ) < return false ; >

$_SESSION [ 'oauth_token_secret' ] = $result [ 'oauth_token_secret' ] ;

\Utils :: redirect ( self :: URL_AUTHORIZE . '?oauth_token=' . $result [ 'oauth_token' ] ) ; return true ; >

private static function encode ( $string , $key ) < return base64_encode ( hash_hmac ( "sha1" , $string , $key , true ) ) ; > >

Далее пользователь подтверждает или отклоняет доступ приложению к своему аккаунту. В любом случае произойдёт перенаправление на URL_CALLBACK. Логика не отличается от остальных сервисов:

if ( ! empty ( $_GET [ 'denied' ] ) ) < // Пользователь отклонил доступ die ( 'denied' ) ; > elseif ( empty ( $_GET [ 'oauth_token' ] ) || empty ( $_GET [ 'oauth_verifier' ] ) ) < // Самый первый запрос OAuthTwitter :: goToAuth ( ) ; > else < // Ответ пришёл удачный // Запрос токена доступа и данных пользователя >

Запрос токена доступа и данных пользователя, вновь с encode:

class OAuthTwitter < const URL_GET_TOKEN = 'https://api.twitter.com/oauth2/token' ; const URL_ACCESS_TOKEN = 'https://api.twitter.com/oauth/access_token' ; const URL_USER_DATA = 'https://api.twitter.com/1.1/users/show.json' ;

private static $token ; public static $userId ; public static $userData ;

public static function getToken ( $oauth_token , $oauth_verifier ) < $oauth_nonce = md5 ( uniqid ( rand ( ) , true ) ) ; $oauth_timestamp = time ( ) ; $oauth_token_secret = $_SESSION [ 'oauth_token_secret' ] ;

$oauth_base_text = "GET&" . urlencode ( self :: URL_ACCESS_TOKEN ) . "&" . urlencode ( "oauth_consumer_key color:#393">. self :: CONSUMER_KEY . "&" . "oauth_nonce color:#393">. $oauth_nonce . "&" . "oauth_signature_method=HMAC-SHA1&" . "oauth_token color:#393">. $oauth_token . "&" . "oauth_timestamp color:#393">. $oauth_timestamp . "&" . "oauth_verifier color:#393">. $oauth_verifier . "&" . "oauth_version=1.0" ) ;

$key = self :: CONSUMER_SECRET . "&" . $oauth_token_secret ; $oauth_signature = self :: encode ( $oauth_base_text , $key ) ;

$url = self :: URL_ACCESS_TOKEN . '?oauth_consumer_key=' . self :: CONSUMER_KEY . '&oauth_nonce=' . $oauth_nonce . '&oauth_signature_method=HMAC-SHA1' . '&oauth_token=' . urlencode ( $oauth_token ) . '&oauth_timestamp=' . $oauth_timestamp . '&oauth_verifier=' . urlencode ( $oauth_verifier ) . '&oauth_signature=' . urlencode ( $oauth_signature ) . '&oauth_version=1.0' ;

if ( ! ( $response = @ file_get_contents ( $url ) ) ) < return false ; >

parse_str ( $response , $result ) ;

if ( empty ( $result [ 'oauth_token' ] ) || empty ( $result [ 'user_id' ] ) ) < return false ; >

self :: $token = $result [ 'oauth_token' ] ; self :: $userId = $result [ 'user_id' ] ;

public function getUser ( ) < $data = array ( 'grant_type' => 'client_credentials' , ) ; $opts = array ( 'http' => array ( 'method' => 'POST' , 'header' => "Content-type: application/x-www-form-urlencoded;charset=UTF-8 \r \n " . 'Authorization: Basic ' . base64_encode ( self :: CONSUMER_KEY . ':' . self :: CONSUMER_SECRET ) . " \r \n " , 'content' => http_build_query ( $data ) ) ) ; $context = stream_context_create ( $opts ) ;

if ( ! ( $response = @ file_get_contents ( self :: URL_GET_TOKEN , false , $context ) ) ) < return false ; > $result = json_decode ( $response , true ) ;

if ( empty ( $result [ 'access_token' ] ) ) < return false ; >

$opts = array ( 'http' => array ( 'method' => 'GET' , 'header' => "Content-type: application/x-www-form-urlencoded;charset=UTF-8 \r \n " . 'Authorization: Bearer ' . $result [ 'access_token' ] . " \r \n " , ) ) ;

$url = self :: URL_USER_DATA . '?user_id=' . self :: $userId ; if ( ! ( $response = @ file_get_contents ( $url , false , stream_context_create ( $opts ) ) ) ) < return false ; >

$user = json_decode ( $response , true ) ; if ( empty ( $user ) ) < return false ; >

return self :: $userData = $user ; > >

$userData содержит много данных: id, логин, имя, страна, последний статус и многое другое. Вот основные из них:

Array ( [ id ] => 783214 [ name ] => Twitter [ screen_name ] => twitter [ location ] => San Francisco , CA [ description ] => Your official source for news , updates and tips from Twitter , Inc .

📎📎📎📎📎📎📎📎📎📎