PHP  »  Articoli  »  Symfony 

Autenticazione con Facebook in applicazioni Symfony

di: Daniel Londero     31 Gennaio 2012

Esempio di Customer User Provider utilizzando il bundle FOSUserBundle

Il FOSUserBundle è un altro bundle sviluppato dalla comunità che permette di integrare in un'applicazione sviluppata con Symfony2 un sistema di gestione utenti basato su database. Il bundle mette a disposizione un framework molto flessibile per la gestione degli utenti con lo scopo di gestire le operazioni più comuni come il login, la registrazione ed il recupero della password smarrita.

Alcune feature incluse in FOSUserBundle:

  • Gli utenti possono essere memorizzati utilizzando Doctrine ORM, MondoDB/CouchDB ODM  oppure Propel
  • Supporto per il processo di registrazione con servizio di conferma via email opzionale
  • Supporto per il recupero delle password smarrite

Nel caso si volesse utilizzare anche il bundle FOSUserBundle per la gestione di altri sistemi di accesso/gestione degli utenti sarà necessario aggiungere un servizio per il custom user provider da impostare nella sezione "provider" del file config.yml:

services:
    my.facebook.user:
        class: AcmeMyBundleSecurityUserProviderFacebookProvider
        arguments:
            facebook: "@fos_facebook.api"
            userManager: "@fos_user.user_manager"
            validator: "@validator"
            container: "@service_container"

<?php

namespace AcmeMyBundleSecurityUserProvider;

use SymfonyComponentSecurityCoreExceptionUsernameNotFoundException;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use BaseFacebook;
use FacebookApiException;

class FacebookProvider implements UserProviderInterface
{
    /**
    * @var Facebook
    */
    protected $facebook;
    protected $userManager;
    protected $validator;

    public function __construct(BaseFacebook $facebook, $userManager, $validator)
    {
        $this->facebook = $facebook;
        $this->userManager = $userManager;
        $this->validator = $validator;
    }

    public function supportsClass($class)
    {
        return $this->userManager->supportsClass($class);
    }

    public function findUserByFbId($fbId)
    {
        return $this->userManager->findUserBy(array('facebookID' => $fbId));
    }

    public function loadUserByUsername($username)
    {
        $user = $this->findUserByFbId($username);

        try {
            $fbdata = $this->facebook->api('/me');
        } catch (FacebookApiException $e) {
            $fbdata = null;
        }

        if (!empty($fbdata)) {
            if (empty($user)) {
                $user = $this->userManager->createUser();
                $user->setEnabled(true);
                $user->setPassword('');
                $user->setAlgorithm('');
            }

            // TODO use http://developers.facebook.com/docs/api/realtime
            $user->setFBData($fbdata);

            if (count($this->validator->validate($user, 'Facebook'))) {
                // TODO: the user was found obviously, but doesnt match our expectations, do something smart
                throw new UsernameNotFoundException('The facebook user could not be stored');
            }
            $this->userManager->updateUser($user);
        }

        if (empty($user)) {
            throw new UsernameNotFoundException('The user is not authenticated on facebook');
        }

        return $user;
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$this->supportsClass(get_class($user)) || !$user->getFacebookId()) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
    }

        return $this->loadUserByUsername($user->getFacebookId());
    }
}

Infine sarà necessario aggiungere i metodi getFacebookId() e setFBData() al modello User. Il seguente esempio aggiunge anche le proprietà firstname e lastname:

<?php

namespace AcmeMyBundleEntity;

use FOSUserBundleEntityUser as BaseUser;

class User extends BaseUser 
{
    /**
    * @var string
    */
    protected $firstname;

    /**
    * @var string
    */
    protected $lastname;

    /**
    * @var string
    */
    protected $facebookID;


    public function serialize()
    {
        return serialize(array($this->facebookId, parent::serialize()));
    }

    public function unserialize($data)
    {
        list($this->facebookId, $parentData) = unserialize($data);
        parent::unserialize($parentData);
    }



    /**
    * @return string
    */
    public function getFirstname()
    {
        return $this->firstname;
    }

    /**
    * @param string $firstname
    */
    public function setFirstname($firstname)
    {
        $this->firstname = $firstname;
    }

    /**
    * @return string
    */
    public function getLastname()
    {
        return $this->lastname;
    }

    /**
    * @param string $lastname
    */
    public function setLastname($lastname)
    {
        $this->lastname = $lastname;
    }

    /**
    * Get the full name of the user (first + last name)
    * @return string
    */
    public function getFullName()
    {
        return $this->getFirstName() . ' ' . $this->getLastname();
    }

    /**
    * @param string $facebookID
    * @return void
    */
    public function setFacebookID($facebookID)
    {
        $this->facebookID = $facebookID;
        $this->setUsername($facebookID);
        $this->salt = '';
    }

    /**
    * @return string
    */
    public function getFacebookID()
    {
        return $this->facebookID;
    }

    /**
    * @param Array
    */
    public function setFBData($fbdata)
    {
        if (isset($fbdata['id'])) {
            $this->setFacebookID($fbdata['id']);
            $this->addRole('ROLE_FACEBOOK');
        }
        if (isset($fbdata['first_name'])) {
            $this->setFirstname($fbdata['first_name']);
        }
        if (isset($fbdata['last_name'])) {
            $this->setLastname($fbdata['last_name']);
        }
        if (isset($fbdata['email'])) {
            $this->setEmail($fbdata['email']);
        }
    }
}

Conclusione

Abbiamo visto come integrare l'accesso ad un'applicazione Symfony2 sfruttando il bundle FOSFacebookBundle sviluppato dalla comunità. Utilizzare soluzioni già sviluppate e testate è alla base della politica di non reinventare la ruota: il tempo risparmiato per la risoluzione di questo problema può essere utilizzato per focalizzare il nostro lavoro su altre parti di business logic dell'applicazione che sicuramente aggiungeranno maggiore valore all'applicazione.

Guide PHP

Guida Yii Framework

Come creare applicazioni Web in modo semplice e veloce con il...

Guida Zend Framework

Diventate professionisti dello sviluppo Web. Zend Framework è lo...

Guida Applicazioni Facebook con PHP

Come realizzare un'applicazione per Facebook. Dalle basi della...

Altre guide

Newsletter @PHP

Ogni lunedì, direttamente nella tua e-mail: script, articoli, guide e tutorial su PHP, MySQL e Apache.

Iscriviti alla newsletter

Altre newsletter

Corsi in aula

Corso PHP per Webmaster

11 Giugno 2012 a Milano
Disponibilità: 7 Posti

Corso Google AdWords Base

25 Giugno 2012 a Milano
Disponibilità: 7 Posti

Corso Google AdWords Base

05 Giugno 2012 a Roma
Disponibilità: 7 Posti