Статьи

Аутентификация в социальных сетях: Twitter и Facebook

В предыдущих частях этой серии мы создавали наши начальные интерфейсы, настраивали нашу функцию входа в Google+ и говорили о том, как мы можем объединить наши учетные записи. В этой статье мы интегрируем Twitter и Facebook в наше приложение. Вы увидите много сходства со статьей Google+ , поэтому, если вы сможете легко следовать этой статье , у вас не будет особых проблем с этой статьей . Если вы еще не читали эту статью, я предлагаю вам сначала прочитать ее, прежде чем продолжить эту статью.

Вы можете просмотреть код для всех статей на этой странице Github .

Аутентификация в твиттере

Еще раз, мы начнем с создания следующего каталога: src/SitePoint/SocialLogin/Twitter В этом каталоге мы создаем класс TwitterLogin Этот класс реализует интерфейс SocialLoginInterface Убедитесь, что свойство, называемое service

Как и в Google+, у Twitter есть некоторые особые потребности, чтобы мы могли войти в систему. Поэтому убедитесь, что в классе присутствуют следующие 3 свойства:

  • ID клиента
  • ключ
  • URL обратного вызова

Поскольку все 3 свойства необходимы для работы нашего приложения, наш конструктор получит эти 3 переменные в качестве параметров и установит свойства.

До сих пор ваш код должен выглядеть так же, как первый пример в статье Google+ .

Наш следующий шаг — создать наш сервис Twitter. Мы будем использовать ту же библиотеку OAuth и установим соединение в методе init.

Прежде чем мы сможем начать, мы должны добавить некоторые операторы использования в начало нашего класса.

 use OAuth\ServiceFactory;
use OAuth\OAuth1\Service\Twitter;
use OAuth\Common\Storage\Session;
use OAuth\Common\Consumer\Credentials;

Все для нашего метода init теперь присутствует. Время установить нашу связь с Twitter. Мы делаем это с помощью основных примеров библиотеки OAuth, которую мы используем.

 /**
     * Initializes our service
     */
    public function init()
    {
        $storage = new Session();
        $serviceFactory = new ServiceFactory();
        $credentials = new Credentials($this->clientId, $this->key, $this->callbackUrl);
        $this->service = $serviceFactory->createService('twitter', $credentials, $storage);

        return $this;
    }

Наш сервис настроен, поэтому мы можем продолжить, заполнив другие методы интерфейса. Мы начнем с метода getLoginUrl Этот метод возвращает URL-адрес, на который вы будете перенаправлять пользователя.

 /**
 * Returns the login url for the social network
 *
 * @return string
 */
public function getLoginUrl()
{
        $token = $this->service->requestRequestToken();
        return $this->service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
}

Вы можете заметить, что этот метод (и следующий, который мы обсудим) немного отличается от статьи в Google+. Это связано с тем, что Google+ использует OAuth 2, а Twitter использует OAuth 1. Twitter был одной из первых компаний, использовавших OAuth, поскольку в то время первоначальный создатель OAuth работал в Twitter. Твиттер все еще использует OAuth 1, хотя они продвигаются к переходу на OAuth 2.

Следующий метод для определения — метод loginCallback Когда пользователь принимает данные Twitter для обмена с вашим приложением, он будет перенаправлен обратно на URL-адрес, который вы определили как callbackUrl Когда пользователь запрашивает этот URL, вы должны вызвать метод loginCallback

Если все прошло хорошо, теперь мы можем получить данные из Twitter.

 /**
 * Handles the login callback from the social network
 *
 * @return SocialUserInterface
 */
    public function loginCallback()
    {
        $storage = new Session();
        $token = $storage->retrieveAccessToken('Twitter');

        $this->service->requestAccessToken(
            $_GET['oauth_token'],
            $_GET['oauth_verifier'],
            $token->getRequestTokenSecret()
        );
        $userData = json_decode($this->service->request('account/verify_credentials.json'), true);
        $twitterUser = new TwitterUser($userData);
        return $twitterUser;
    }

На этот раз мы используем класс с именем TwitterUserSocialUserInterface Однако этого класса еще нет. Время создать это!

Пользователь Twitter

Twitter возвращает данные другим способом, нежели Google+, поэтому нам нужно снова нормализоваться. Нам нужно создать класс с именем TwitterUserSocialUserInterface

В этом случае конструктор этого класса ожидает необработанные данные Twitter. В каждом получателе мы будем извлекать нужные данные из необработанных данных. В конце ваш класс TwitterUser

 <?php

namespace SitePoint\SocialLogin\Twitter;

use SitePoint\SocialLogin\Interfaces\SocialUserInterface;

class TwitterUser implements SocialUserInterface {

    /**
     * @var mixed user data
     */
    private $userData;

    /**
     * Constructor.
     *
     * @param $userData mixed Raw social network data for this particular user
     */
    public function __construct($userData)
    {
        $this->userData = $userData;
    }

    /**
     * Get the provider name
     *
     * @return string
     */
    public function getProvider()
    {
        return "twitter";
    }

    /**
     * Get the UID of the user
     *
     * @return string
     */
    public function getUid()
    {
        if(array_key_exists('id', $this->userData)) {
            return $this->userData['id'];
        }
        return null;
    }

    /**
     * Get the first name of the user
     *
     * @return string
     */
    public function getFirstname()
    {
        if(array_key_exists('name', $this->userData)) {
            list($firstname, $lastname) = explode(" ", $this->userData['name']); // TODO: Of course you have to make this smarter
            return $firstname;
        }
        return null;
    }

    /**
     * Get the last name of the user
     *
     * @return string
     */
    public function getLastname()
    {
        if(array_key_exists('name', $this->userData)) {
            list($firstname, $lastname) = explode(" ", $this->userData['name']); // TODO: Of course you have to make this smarter
            return $lastname;
        }
        return null;
    }

    /**
     * Get the username
     *
     * @return string
     */
    public function getUsername()
    {
        if(array_key_exists('screen_name', $this->userData)) {
            return $this->userData['screen_name'];
        }

        return null;
    }

    /**
     * Get the emailaddress
     *
     * @return string
     */
    public function getEmailAddress()
    {
        return null;
    }

    /**
     * Get the city
     *
     * @return string
     */
    public function getCity()
    {
        if(array_key_exists('location', $this->userData)) {
            return $this->userData['location'];
        }
        return null;
    }

    /**
     * Get the birthdate
     *
     * @return string
     */
    public function getBirthDate()
    {
        return null;
    }

    /**
     * Get the gender
     *
     * @return string
     */
    public function getGender()
    {
        return null;
    }
}

Вы можете заметить, что у нас намного меньше информации, чем с Google+. Твиттер просто не делится такой большой информацией. Например, нам не хватает адреса электронной почты, хотя это одно из самых распространенных полей, которые вы хотели бы иметь в своем приложении.

Единственное, что вы можете сделать, это, после входа в Twitter, попросить пользователя ввести свой адрес электронной почты и сохранить его в своей базе данных. Кроме этого, вы можете попытаться объединить учетную запись Twitter с уже заданной учетной записью, как в предыдущей части этой серии.

Логин в фейсбук

Обладая знаниями, которые вы получили из объяснений в Google+ и Twitter, вам будет легко настроить версию Facebook. Здесь у вас есть полная реализация для класса входа в систему.

 <?php

namespace SitePoint\SocialLogin\Facebook;

use SitePoint\SocialLogin\Interfaces\SocialLoginInterface;
use OAuth\ServiceFactory;
use OAuth\OAuth2\Service\Facebook;
use OAuth\Common\Storage\Session;
use OAuth\Common\Consumer\Credentials;

class FacebookLogin implements SocialLoginInterface {

    /**
     * Facebook service
     *
     * @var string
     */
    protected $service;

    /**
     * OAuth client ID
     *
     * @var string
     */
    protected $clientId;

    /**
     * OAuth key
     *
     * @var string
     */
    protected $key;

    /**
     * Callback url
     *
     * @var string
     */
    protected $callbackUrl;

    /**
     * Constructor.
     *
     * @param $clientId string
     * @param $key string
     * @param $callbackUrl string
     */
    public function __construct($clientId, $key, $callbackUrl)
    {
        $this->clientId = $clientId;
        $this->key = $key;
        $this->callbackUrl = $callbackUrl;
    }

    /**
     * Initializes our service
     */
    public function init()
    {
        $storage = new Session();
        $serviceFactory = new ServiceFactory();
        $credentials = new Credentials($this->clientId, $this->key, $this->callbackUrl);
        $this->service = $serviceFactory->createService(
            'facebook',
            $credentials,
            $storage,
            array(
                Facebook::SCOPE_EMAIL,
                Facebook::SCOPE_USER_BIRTHDAY,
                Facebook::SCOPE_USER_LOCATION
            )
        );

        return $this;
    }

    /**
     * Returns the login url for the social network
     *
     * @return string
     */
    public function getLoginUrl()
    {
        return $this->service->getAuthorizationUri();
    }

    /**
     * Handles the login callback from the social network
     *
     * @param string $accessCode
     *
     * @return SocialUserInterface
     */
    public function loginCallback($accessCode)
    {
        $token = $this->service->requestAccessToken($accessCode);

        // Send a request with it
        $userData = json_decode($this->service->request('/me'), true);
        $facebookUser = new FacebookUser($userData);
        return $facebookUser;
    }
}

Вы можете заметить, что я определил некоторые области при создании сервиса Facebook. Определив эти области, я могу получить некоторые дополнительные детали от пользователя. В этом случае я также собираю адрес электронной почты, день рождения и местоположение. Учтите, что чем больше данных вы соберете, тем больше у вас шансов, что пользователь откажется войти в приложение.

Пользователь facebook

Пользовательский класс еще проще и не содержит никаких сюрпризов. Когда закончите, это должно выглядеть так.

 <?php

namespace SitePoint\SocialLogin\Facebook;

use SitePoint\SocialLogin\Interfaces\SocialUserInterface;

class FacebookUser implements SocialUserInterface {

    /**
     * @var mixed user data
     */
    private $userData;

    /**
     * Constructor.
     *
     * @param $userData mixed Raw social network data for this particular user
     */
    public function __construct($userData)
    {
        $this->userData = $userData;
    }

    /**
     * Get the provider name
     *
     * @return string
     */
    public function getProvider()
    {
        return "facebook";
    }

    /**
     * Get the UID of the user
     *
     * @return string
     */
    public function getUid()
    {
        if(array_key_exists('id', $this->userData)) {
            return $this->userData['id'];
        }
        return null;
    }

    /**
     * Get the first name of the user
     *
     * @return string
     */
    public function getFirstname()
    {
        if(array_key_exists('first_name', $this->userData)) {
            return $this->userData['first_name'];
        }
        return null;
    }

    /**
     * Get the last name of the user
     *
     * @return string
     */
    public function getLastname()
    {
        if(array_key_exists('last_name', $this->userData)) {
            return $this->userData['last_name'];
        }
        return null;
    }

    /**
     * Get the username
     *
     * @return string
     */
    public function getUsername()
    {
        if(array_key_exists('name', $this->userData)) {
            return str_replace(" ", "_", $this->userData['name']);
        }
        return null;
    }

    /**
     * Get the emailaddress
     *
     * @return string
     */
    public function getEmailAddress()
    {
        if(array_key_exists('email', $this->userData)) {
            return $this->userData['email'];
        }
        return null;
    }

    /**
     * Get the city
     *
     * @return string
     */
    public function getCity()
    {
        if(array_key_exists('location', $this->userData)) {
            return $this->userData['location'];
        }
        return null;
    }

    /**
     * Get the birthdate
     *
     * @return string
     */
    public function getBirthDate()
    {
        if(array_key_exists('birthday', $this->userData)) {
            return $this->userData['birthday'];
        }
        return null;
    }

    /**
     * Get the gender
     *
     * @return string
     */
    public function getGender()
    {
        if(array_key_exists('location', $this->userData)) {
            return $this->userData['location']['name'];
        }
        return null;
    }
}

Быстрый тест

Если вы хотите выполнить быстрый тест для проверки кода, клонируйте репозиторий Github на локальный компьютер и переключитесь на ветку с именем part4 В этой ветке вы увидите testTwitter.phptestFacebook.php Вы можете заполнить сведения об API обеих служб и запустить файл в своем браузере. При запросе страницы вы будете перенаправлены на страницу социальной сети с просьбой поделиться информацией.

Когда вы нажмете «Принять», вы будете перенаправлены обратно на страницу, которую вы настроили в качестве URL обратного вызова, с указанием вашего имени и фамилии.

Вывод

В этой статье мы взяли основу, которую мы заложили в предыдущих статьях, и продолжили работу над этим. Рядом с Google+ теперь мы можем войти через Twitter и Facebook. Во всех случаях мы возвращаем нормализованный пользовательский объект, который мы можем добавить в нашу собственную пользовательскую систему. С этой статьей мы подошли к концу этой серии. Это дало вам некоторое представление о том, как обращаться с пакетами, не связанными с социальными сетями или инфраструктурой? Не стесняйтесь задавать любые вопросы в комментариях ниже!