Slyweb
На разработку сайта! Скидки 50%!

Zend FrameWork 2 и авторизации c Twitter

jQuery и CSS

Для мультиязычных сайтов необходима авторизация из социальных сетей, так как по статистике, более 50 % пользователей моих сайтов зарегистрированы из социальных сетей, а именно – из twitter и facebook.

Более того уровень доверия к таким сайтам намного больше, чем к тем у которых до сих пор отсутствует система авторизации на основе социальных сетей.

Что нужно для авторизации пользователей.

  • Ключ приложения twitter и секрет (секретная фраза) эти данные можно плучить на сарнице dev.twitter.com/apps, создав новое приложение.
  • Zend FrameWork 2
  • модули для Zend FrameWork 2 - ZfcUser и ZfcBase
  • Модуль Hybridauth v 2.0.10 hybridauth-v2.0.10.zip

Модуль ZfcUser и комплект скриптов hybridauth-v2.0.10.zip

Первый не сложно найти, второй располагается по адресу - hybridauth

Итак, давайте начнём со скачивания архива hybridauth-v2.0.10.zip После этого скачайте ZfcUser - ZfcBase и ZfcUser.

ZfcUser и ZfcBase два модуля, первый из которых отвечает за авторизацию пользователя, второй содержит вспомогательные классы для изменения данных пользователя и обработки события регистрации и авторизации пользователя.

Их установка не сложна - скачайте и распакуйте в директорию с модулями Zend FrameWork 2, затем подключите их в файле /config/application.config.php

Предположим Вы имеете структуру из следующих модулей (глобальный конфигурационный файл "application.config.php"):

  • Код
  • Чистый код
  • Копировать в буфер
  1.<?php
  2.return array(
  3.    'modules' => array(
  4.        'Application',
  5.        'Suggest',
  6.        'Search',
  7.        'Album',
  8.        'ZfcUser',
  9.        'ZfcBase',
10.    ),
11.    'module_listener_options' => array(
12.        'config_glob_paths'    => array(
13.            'config/autoload/{,*.}{global,local}.php',
14.        ),
15.        'module_paths' => array(
16.            './module',
17.            './vendor',
18.        ),
19.
20.    )
21.
22.);
23.

        

После этого, необходимо настроить Hybridauth, для этого отредактируйте файл config.php, который находится в директории \hybridauth\hybridauth\ следующим образом, - замените полученными при регистрации вашего приложения (https://dev.twitter.com/apps) ключом и секретной фразой параметры «keys» и «secret» в файле /hybridauth/hybridauth/config.php:

  • Код
  • Чистый код
  • Копировать в буфер
  1.Twitter" => array (
  2.                "enabled" => true,
  3.                "keys"    => array ( "key" => "***********", "secret" => "*************************" )
  4.            ),
  5.

        

После этого нужно создать новое действие, которое будет являтся страницей авторизацией из twitter.com на вашем сайте, - например:

  • Код
  • Чистый код
  • Копировать в буфер
  1./**
  2.     * Login from twitter
  3.     */
  4.    public function twitterAction()
  5.    {
  6.
  7.
  8.            // подключение нужных файлов
  9.            $config = $_SERVER['DOCUMENT_ROOT'] . '/hybridauth/hybridauth/config.php';
10.            require_once( $_SERVER['DOCUMENT_ROOT']."/hybridauth/hybridauth/Hybrid/Auth.php" );
11.
12.            try{
13.                // инициализация hybridauth
14.                $hybridauth = new \Hybrid_Auth( $config );
15.
16.                // автоматическая проверка подключения пользователя к twitter
17.                $twitter = $hybridauth->authenticate( "Twitter" );
18.
19.                // возвращает TRUE или False до того как вы получите доступ к twitter
20.                $is_user_logged_in = $twitter->isUserConnected();
21.
22.                // получение данных пользователя
23.                $user_profile = $twitter->getUserProfile();
24.
25.                // доступ к данным из twitter
26.                echo "Првиет! Ты в twitter: <b>{$twitter->id}</b><br />";
27.                echo "Вы вошли как: <b>{$user_profile->displayName}</b><br />";
28.                echo "и ваш id в twitter: <b>{$user_profile->identifier}</b><br />";
29.
30.                // дополнение
31.                echo "<pre>" . print_r( $user_profile, true ) . "</pre><br />";
32.
33.                // расскоментируйте эту линию для того чтобы получить список выших друзей
34.                // $twitter->getUserContacts();
35.
36.                // расскоментируйте эту линию для написания постов
37.                // $twitter->setUserStatus( "Hello world!" );
38.
39.                // пример того как получить данные с hybridauth
40.                //     Вернёт количество друзей, последователей, статусы и любимые пользователи.
41.                //     https://dev.twitter.com/docs/api/1/get/account/totals
42.                $account_totals = $twitter->api()->get( 'account/totals.json' );
43.
44.                // вывод полученных данных
45.                echo "Статистика вашего аккаунта в Twitter:<br /><pre>" . print_r( $account_totals, true ) . "</pre>";
46.                
47.                $data = array('username'=>$user_profile->firstName,'lastname'=>$user_profile->lastname,'userinfo'=>$user_profile->description,'identifier'=>$user_profile->identifier);
48.                $request = $this->getRequest();                
49.                $service = $this->getUserService();
50.                $user = $service->RegisterFromTwitter($data);
51.                // нужно или нет?
52.                $hybridauth->restoreSessionData();
53.                // нужно или нет?
54.                if($user) {
55.                        if ($service->getOptions()->getLoginAfterRegistration()) {
56.                        $identityFields = $service->getOptions()->getAuthIdentityFields();
57.                        if (in_array('email', $identityFields)) {
58.                            $post['identity'] = $user->getEmail();
59.                        } elseif(in_array('username', $identityFields)) {
60.                            $post['identity'] = $user->getUsername();
61.                        }
62.                        $post['credential'] = $post['password'];
63.                        $post['twitter'] = 1;
64.                        $request->setPost(new Parameters($post));
65.                        return $this->forward()->dispatch('zfcuser', array('action' => 'authenticate','twitter'=>$post['twitter']));
66.                    }
67.                    
68.                    // TODO: Add the redirect parameter here...
69.                    return $this->redirect()->toUrl($this->url()->fromRoute('zfcuser/login') . ($request ? '?redirect='.$request : ''));
70.                }
71.                // logout
72.                echo "Logging out..";
73.                
74.            }
75.            catch( Exception $e ){
76.                // In case we have errors 6 or 7, then we have to use Hybrid_Provider_Adapter::logout() to
77.                // let hybridauth forget all about the user so we can try to authenticate again.
78.
79.                // Display the recived error,
80.                // to know more please refer to Exceptions handling section on the userguide
81.                switch( $e->getCode() ){
82.                    case 0 : echo "Unspecified error."; break;
83.                    case 1 : echo "Hybridauth configuration error."; break;
84.                    case 2 : echo "Provider not properly configured."; break;
85.                    case 3 : echo "Unknown or disabled provider."; break;
86.                    case 4 : echo "Missing provider application credentials."; break;
87.                    case 5 : echo "Authentification failed. "
88.                             . "The user has canceled the authentication or the provider refused the connection.";
89.                         break;
90.                    case 6 : echo "User profile request failed. Most likely the user is not connected "
91.                             . "to the provider and he should to authenticate again.";
92.                         $twitter->logout();
93.                         break;
94.                    case 7 : echo "User not connected to the provider.";
95.                         $twitter->logout();
96.                         break;
97.                    case 8 : echo "Provider does not support this feature."; break;
98.                }
99.
100.                // well, basically your should not display this to the end user, just give him a hint and move on..
101.                echo "<br /><br /><b>Original error message:</b> " . $e->getMessage();
102.
103.                echo "<hr /><h3>Trace</h3> <pre>" . $e->getTraceAsString() . "</pre>";
104.
105.                /*
106.                    // If you want to get the previous exception - PHP 5.3.0+
107.                    // http://www.php.net/manual/en/language.exceptions.extending.php
108.                    if ( $e->getPrevious() ) {
109.                        echo "<h4>Previous exception</h4> " . $e->getPrevious()->getMessage() . "<pre>" . $e->getPrevious()->getTraceAsString() . "</pre>";
110.                    }
111.                */
112.            }
113.
114.
115.    }

        

Обратите внимание необходимо правильно указать пути до основной директории hybridauth! Заранее скажу, что так писать код не совсем соответствует правилам Zend Framework, по правилам нужно вынести подключаемые классы HybridAuth в отдельную директорю Plugin, основного класса и подключать их в качетсве плагина Zend FrameWork, но в целях упрощения и обучения, думаю, так можно поступить на первое время.

  • Код
  • Чистый код
  • Копировать в буфер
  1.$config = $_SERVER['DOCUMENT_ROOT'] . '/hybridauth/hybridauth/config.php';
  2.require_once( $_SERVER['DOCUMENT_ROOT']."/hybridauth/hybridauth/Hybrid/Auth.php" );

        

дальше мы проверяем, был ли осуществлён ранее вход с twitter

  • Код
  • Чистый код
  • Копировать в буфер
  1.// automatically try to login with Twitter
  2.$twitter = $hybridauth->authenticate( "Twitter" );

        

после этого получаем данные и выводим

  • Код
  • Чистый код
  • Копировать в буфер
  1.// get the user profile
  2.$user_profile = $twitter->getUserProfile();
  3.
  4.// access user profile data
  5.echo "Ohai there! U are connected with: <b>{$twitter->id}</b><br />";
  6.echo "As: <b>{$user_profile->displayName}</b><br />";
  7.echo "And your provider user identifier is: <b>{$user_profile->identifier}</b><br />";
  8.
  9.// or even inspect it
10.echo "<pre>" . print_r( $user_profile, true ) . "</pre><br />";
11.

        

выводим дополнительную статистику из аккаунта twitter

  • Код
  • Чистый код
  • Копировать в буфер
  1.$account_totals = $twitter->api()->get( 'account/totals.json' );

        
  • Код
  • Чистый код
  • Копировать в буфер
  1.$account_totals = $twitter->api()->get( 'account/totals.json' );
  2.
  3.// print recived stats
  4.echo "Here some of yours stats on Twitter:<br /><pre>" . print_r( $account_totals, true ) . "</pre>";
  5.

        

с полученными данными делаем всё что угодно:

  • Код
  • Чистый код
  • Копировать в буфер
  1.$data = array('username'=>$user_profile->firstName,'lastname'=>$user_profile->lastname,'userinfo'=>$user_profile->description,'identifier'=>$user_profile->identifier);
  2.$request = $this->getRequest();                
  3.$service = $this->getUserService();
  4.$user = $service->RegisterFromTwitter($data);

        

$service – переменная, хранящая результат работы класса «ServiceManager», по сути своей - это класс для доступа к другим классам нашего модуля. Полная информация о том, что такое «ServiceManager» – ServiceManager

  • Код
  • Чистый код
  • Копировать в буфер
  1.    public function getUserService()
  2.    {
  3.        if (!$this->userService) {
  4.            $this->userService = $this->getServiceLocator()->get('zfcuser_user_service');
  5.        }
  6.        return $this->userService;
  7.    }
  8.

        

'zfcuser_user_service' – обозначение вспомогательного класса (сервиса), который находится в директории \module\ZfcUser\src\ZfcUser\Service\ в файле User.php Далее getUserService будет содержать результат выполнения метода

  • Код
  • Чистый код
  • Копировать в буфер
  1.$user = $service->RegisterFromTwitter($data);
  2.
  3.
  4./**
  5.     * createRegisterFromTwitter
  6.     *
  7.     * @param array $data
  8.     * @return \ZfcUser\Entity\UserInterface
  9.     * @throws Exception\InvalidArgumentException
10.     */
11.    public function RegisterFromTwitter(array $data)
12.    {
13.
14.
15.        $user = new \ZfcUser\Entity\User();
16.
17.        $identifier = $this->getUserMapper()->findByIdentifier($data['identifier']);
18.
19.            $user->setMiddlename($data['middlename']);
20.            $user->setLastname('');
21.            $user->setMiddlename('');
22.            $user->setEmail($data['identifier'].'@nomail.com');
23.            $user->setPassword('');
24.            $user->setRegion('');
25.            $user->setCity('');
26.            $user->setAddress('');
27.            $user->setSex('');
28.            $user->setUserinfo($data['userinfo']);
29.            $user->setAvatarType(0);
30.            $user->setAvatar(0);
31.            $user->setIdentifier($data['identifier']);
32.            $user->setTypesocnet(1);
33.            if($identifier) {
34.                $user->setId($identifier->getId());
35.            } else {
36.            
37.            }
38.        if ($this->getOptions()->getEnableUsername()) {
39.            $user->setUsername($data['username']);
40.        }
41.        if ($this->getOptions()->getEnableDisplayName()) {
42.            $user->setDisplayName($data['display_name']);
43.        }
44.        
45.        if($identifier) {
46.            $this->getUserMapper()->update($user);
47.        } else {
48.            $this->getEventManager()->trigger(__FUNCTION__, $this, array('user' => $user, 'form' => $form));
49.            $this->getUserMapper()->insert($user);
50.            $this->getEventManager()->trigger(__FUNCTION__.'.post', $this, array('user' => $user, 'form' => $form));    
51.        }
52.
53.
54.
55.        return $user;
56.    }
57.

        

Интерфейс пользователя нужен для установки и модификации персональных данных пользователя, он поставляется по умолчанию вместе с модулем «ZfcUser»: $user = new \ZfcUser\Entity\User();

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

  • Код
  • Чистый код
  • Копировать в буфер
  1.$identifier = $this->getUserMapper()->findByIdentifier($data['identifier']);

        

findByIdentifier может быть следующего содержания и находится по адресу \module\ZfcUser\src\ZfcUser\Mapper\User.php

  • Код
  • Чистый код
  • Копировать в буфер
  1.    public function findByIdentifier($identifier)
  2.    {
  3.        $select = $this->select()
  4.                     ->from($this->tableName)
  5.                     ->where(array('identifier' => $identifier));
  6.
  7.        $entity = $this->selectWith($select)->current();
  8.        $this->getEventManager()->trigger('find', $this, array('entity' => $entity));
  9.        return $entity;
10.    }
11.

        

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

  • Код
  • Чистый код
  • Копировать в буфер
  1.$user->setMiddlename($data['middlename']);
  2.$user->setLastname('');
  3.$user->setMiddlename('');
  4.$user->setEmail($data['identifier'].'@nomail.com');
  5.$user->setPassword('');
  6.$user->setRegion('');
  7.$user->setCity('');
  8.$user->setAddress('');
  9.$user->setSex('');
10.$user->setUserinfo($data['userinfo']);
11.$user->setAvatarType(0);
12.$user->setAvatar(0);
13.$user->setIdentifier($data['identifier']);
14.$user->setTypesocnet(1);

        

Hybridauth устроен таким образом, что данные ранее полученные от twitter сохраняются в хранилище (сессию) её можно удалить, хотя сделано это больше для тестирования или например, если Вам нужно постоянно отслеживать статус авторизации на сайте twitter, а не получать старые данные.

  • Код
  • Чистый код
  • Копировать в буфер
  1.        // нужно или нет?
  2.        $hybridauth->restoreSessionData();
  3.        // нужно или нет?
  4.

        

После этого остаётся перенаправить пользователя в его аккаунт методом dispatch действию authenticate контроллёра «zfcuser», передав дополнительный параметр 'twitter'=>$post['twitter'] и не обращайте внимание на код после строки "// TODO: Add the redirect parameter here...":

  • Код
  • Чистый код
  • Копировать в буфер
  1.    if($user) {
  2.                        if ($service->getOptions()->getLoginAfterRegistration()) {
  3.                        $identityFields = $service->getOptions()->getAuthIdentityFields();
  4.                        if (in_array('email', $identityFields)) {
  5.                            $post['identity'] = $user->getEmail();
  6.                        } elseif(in_array('username', $identityFields)) {
  7.                            $post['identity'] = $user->getUsername();
  8.                        }
  9.                        $post['credential'] = $post['password'];
10.                        $post['twitter'] = 1;
11.                        $request->setPost(new Parameters($post));
12.                        return $this->forward()->dispatch('zfcuser', array('action' => 'authenticate','twitter'=>$post['twitter']));
13.                    }
14.                    
15.                    // TODO: Add the redirect parameter here...
16.                    return $this->redirect()->toUrl($this->url()->fromRoute('zfcuser/login') . ($request ? '?redirect='.$request : ''));
17.                }
18.
19.

        

Таким образом можно расширить стандартную аутентификацию пользователя! При этом по тому же принципу можно добавить весь набор социальных сетей, которые находятся в Hybridauth:

  • Foursquare
  • LinkedIn
  • MySpace
  • Live
  • Twitter
  • Facebook
  • Google
  • AOL
  • Yahoo
  • OpenID


Александр Ермаков