
guide
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Come usare Facebook per autenticare l’utente in un’applicazione Web sviluppata con Symfony. Descrizione ed esempi pratici d’uso del FOSFacebookBundle per PHP
Un'applicazione web nella gran parte dei casi prevede un meccanismo di registrazione e login. Rifacendosi al concetto dell'easy in/easy out, e tenendo presente che l'utente non è di certo felice di eseguire l'ennesima registrazione con tanto di nuova password da ricordare per utilizzare il nostro servizio, è consigliabile sfruttare quanto messo a disposizione dai maggiori social network in termini di autenticazione. In particolare quelle del più diffuso social network al mondo: Facebook.
Mettere gli utenti nelle condizioni di accedere alla nostra applicazione sfruttando la loro registrazione a Facebook permette all'applicazione stessa di avere già una base utenti potenziale di oltre 800 milioni di persone.
In questo articolo parleremo di come sfruttare l'autenticazione di Facebook sulle applicazioni Symfony utilizzando il bundle FOSFacebookBundle rispettando il presupposto di non reinventare la ruota sfruttando una soluzione messa a disposizione dalla comunità di sviluppatori nata attorno a Symfony.
Nota: la seguente è una traduzione del file README ufficiale di del Bundle FOSFacebookBundle integrata da nostre annotazioni. Si pubblica in questa sede con rispetto della licenza.
Questo bundle semplifica l'integrazione degli SDK PHP e JS di Facebook in un'applicazione Symfony2. Tra le altre cose mette a disposizione un authentication provider che permette agli utenti di eseguire il login su un'applicazione Symfony2 tramite Facebook. Inoltre, sfruttando il supporto per i custom user provider, il login via Facebook può essere integrato con altre soluzioni di autenticazione come quello offerto da un altro bundle molto utile come il FOSUserBundle.
Autenticare un utente richiede l'esecuzione di alcuni passaggi:
Per i passaggi 1 e 2 descritti sopra esistono due opzioni:
Da notare che l'ultima condizione si verifica automaticamente se il primo provider nel primo firewall configurato è associato al FOSFacebookBundle e l'utente accede ad una pagina che richiede autenticazione senza essere autenticato.
Per maggiore documentazione relativa alle applicazione Facebook si può fare riferimento alla documentazione ufficiale di Facebook. Fare riferimento anche alla documentazione ufficiale del SecurityBundle di Symfony, specialmente per i dettagli relativi alla configurazione.
Tutti i passaggi della seguente guida vengono eseguiti su una Symfony Standard Edition che potete scaricare dal sito di Symfony. La scelta tra la versione con vendor o senza di essi dipende dal grado di flessibilità che si vuole per il progetto. Scaricare la versione senza vendor è la scelta ottimale nel caso in cui si abbia a disposizione Git sulla macchina utilizzata per lo sviluppo e si decida inoltre di mettere il progetto sotto controllo di versione (con Git, Svn, …); in questo modo i componenti di Symfony non verranno inseriti direttamente nel repository ma verranno richiamati esternamente.
La versione completa di vendor è pronta all'uso più velocemente ed è consigliata agli utenti meno esperti dato che richiede minori operazioni di setup.
Aggiungere il bundle e l'SDK PHP di Facebook alla directory vendor/:
Aggiungere le seguenti righe al file deps:
[FOSFacebookBundle]
git=git://github.com/FriendsOfSymfony/FOSFacebookBundle.git
target=/bundles/FOS/FacebookBundle
[FacebookSDK]
git=git://github.com/facebook/php-sdk.git
target=/facebook
Aggiungere la seguente riga al file deps.lock (al momento di scrittura di questa guida la tag 1.0.0 rappresenta la versione funzionante del bundle):
FOSFacebookBundle b3bfbfc2898d62ccb3ec697cafe32f374928d49c
Eseguire lo script dei vendor:
./bin/vendors install
$ git submodule add git://github.com/FriendsOfSymfony/FOSFacebookBundle.git vendor/bundles/FOS/FacebookBundle
$ git submodule add git://github.com/facebook/php-sdk.git vendor/facebook
Aggiungere il namespace FOS all'autoloader:
// app/autoload.php
$loader->registerNamespaces(array(
'FOS' => __DIR__.'/../vendor/bundles',
// your other namespaces ));
Aggiungere il bundle al kernel dell'applicazione:
// app/ApplicationKernel.php
public function registerBundles()
{
return array(
// ...
new FOSFacebookBundleFOSFacebookBundle(),
// ...
);
}
Aggiungere le seguenti rotte all'applicazione facendo in modo di farle puntare alle action dell'attuale controller:
#application/config/routing.yml
_security_check:
pattern: /login_check _security_logout:
pattern: /logout #application/config/routing.xml
<route id="_security_check" pattern="/login_check" />
<route id="_security_logout" pattern="/logout" />
Configurare il servizio facebook
nel file di configurazione:
# application/config/config.yml
fos_facebook:
file: %kernel.root_dir%/../vendor/facebook/src/base_facebook.php
alias: facebook
app_id: 123456879
secret: s3cr3t
cookie: true
permissions: [email, user_birthday, user_location]
# application/config/config.xml
<fos_facebook:api
file="%kernel.root_dir%/../vendor/facebook/src/base_facebook.php"
alias="facebook"
app_id="123456879"
secret="s3cr3t"
cookie="true"
>
<permission>email</permission>
<permission>user_birthday</permission>
<permission>user_location</permission>
</fos_facebook:api>
Se non viene incluso un valore per la chiave file
nella configurazione sarà necessario configurare l'applicazione per fare in modo che possa eseguire l'autoload della classe BaseFacebook
.
La seguente configurazione deve essere aggiunta nel caso in cui si voglia utilizzare il security component:
# application/config/config.yml
security:
factories:
- "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
providers:
fos_facebook:
id: fos_facebook.auth
firewalls:
public:
# dal momento che gli utenti anonimi sono accettati non forziamo il login
pattern: ^/.*
fos_facebook:
app_url: "http://apps.facebook.com/appName/"
server_url: "http://localhost/facebookApp/"
anonymous: true
logout:
handlers: ["fos_facebook.logout_handler"]
access_control:
- { path: ^/secured/.*, role: [IS_AUTHENTICATED_FULLY] } # Questa è la rotta protetta da fos_facebook
- { path: ^/.*, role: [IS_AUTHENTICATED_ANONYMOUSLY] }
Sarà necessario aggiungere /secured/
nella configurazione perché questo funzioni. Una configurazione d'esempio è la seguente:
_facebook_secured:
pattern: /secured/
defaults: { _controller: AcmeDemoBundle:Welcome:index }
A scelta è possibile definire una classe da utilizzare come custom user provider o definire il path per il login
# application/config/config.yml
security:
factories:
- "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
providers:
# scegli liberamente il nome del provide
my_fos_facebook_provider:
id: my.facebook.user # vedere "Esempio di Customer User Provider utilizzando il bundle FOSUserBundle" a pagina 4
firewalls:
public:
pattern: ^/.*
fos_facebook:
app_url: "http://apps.facebook.com/appName/"
server_url: "http://localhost/facebookApp/"
login_path: ^/login
check_path: ^/login_check$
default_target_path: /
provider: my_fos_facebook_provider
anonymous: true
logout:
handlers: ["fos_facebook.logout_handler"]
# application/config/config_dev.yml
security:
firewalls:
public:
fos_facebook:
app_url: "http://apps.facebook.com/appName/"
server_url: "http://localhost/facebookApp/app_dev.php/"
A scelta utilizzare il controllo degli accessi per proteggere URL specifici
# application/config/config.yml
security:
# ...
access_control:
- { path: ^/facebook/, role: [ROLE_FACEBOOK] }
- { path: ^/.*, role: [IS_AUTHENTICATED_ANONYMOUSLY] }
Il ruolo ROLE_FACEBOOK
deve essere aggiunto nella classe User (fare riferimento alla classe AcmeMyBundleEntityUser::setFBData()
che vedremo in seguito).
Nota bene: l'ordine delle regole per il controllo degli accessi influisce sul loro funzionamento.
È disponibile un helper per automatizzare il caricamento dell’SDK JavaScript di Facebook e la sua inizializzazione utilizzando i parametri recuperati dal service container. Per utilizzare l’ambiente JavaScript di Facebook sarà necessario aggiungere il seguente codice al layout dell’applicazione subito dopo l’apertura del tag body
:
<body>
<!-- all'interno di un template php -->
<?php echo $view['facebook']->initialize(array('xfbml' => true, 'fbAsyncInit' => 'onFbInit();')) ?>
<!-- all'interno di un template twig -->
{{ facebook_initialize({'xfbml': true, 'fbAsyncInit': 'onFbInit();'}) }}
Da notare che fbAsyncInit
è un parametro necessario per l’esecuzione del codice JavaScript della funzione che si occupa di inizializzare la connessione con Facebook subito dopo la chiamata FB.init();
. La funzione onFbInit();
è necessaria per l’esecuzione di altre funzioni che richiedono FB
inizializzato.
Nel caso in cui si decida di utilizzare il markup XFBML nella nostra applicazione sarà necessario dichiarare il namespace corretto nell’apertura del tag html
:
<html xmlns:fb="http://www.facebook.com/2008/fbml">
Basterà semplicemente aggiungere il codice seguente in uno dei template dell’applicazione:
<!-- all'interno di un template php --> <?php echo $view['facebook']->loginButton(array('autologoutlink' => true)) ?> <!-- all'interno di un template twig --> {{ facebook_login_button({'autologoutlink': true}) }}
Da notare che con questo approccio verranno gestiti solamente il login e la connessione con Facebook. L’azione di autenticare l’utente nella nostra applicazione Symfony2 deve essere ancora invocata. Per fare questo nella maggior parte dei casi sarà necessario ascoltare l’evento auth.login
e successivamente eseguire il redirect al check_path
:
<script>
function goLogIn(){
window.location = "{{ path('_security_check') }}";
}
function onFbInit() {
if (typeof(FB) != 'undefined' && FB != null ) {
FB.Event.subscribe('auth.login', function(response) {
setTimeout(goLogIn,500);
});
}
}
</script>
Una nota di riguardo relativamente al fatto che si imposti un’attesa di 500ms prima di eseguire il redirect per permettere al browser di comunicare con il cookie di Facebook. Evitando questo passaggio si potrà incorrere nel seguente messaggio di errore:
*”L’utente Facebook non può essere recuperato dalla sessione.”*
La rotta _security_check
dovrà puntare al pattern /login_check
per corrispondere alla configurazione vista in precedenza.
Sarà inoltre necessario richiamare l’azione di logout restando in ascolto dell’evento auth.logout
per effettuare il redirect alla rotta logout
:
<script>
function goLogIn(){
window.location = "{{ path('_security_check') }}";
}
function onFbInit() {
if (typeof(FB) != 'undefined' && FB != null ) {
FB.Event.subscribe('auth.login', function(response) {
setTimeout(goLogIn,500);
});
FB.Event.subscribe('auth.logout', function(response) {
window.location = "{{ path('_security_logout') }}";
});
}
}
</script>
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:
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']);
}
}
}
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.
Se vuoi aggiornamenti su Autenticazione con Facebook in applicazioni Symfony inserisci la tua email nel box qui sotto:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
La tua iscrizione è andata a buon fine. Se vuoi ricevere informazioni personalizzate compila anche i seguenti campi opzionali:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
Grazie a Gimp diventa molto semplice simulare la sfocatura dello sfondo all’interno di una fotografia, aumentando così notevolmente la profondità […]
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Come creare applicazioni per il Web con PHP e MySQL per il DBMS.
Tutte le principali tecnologie per diventare uno sviluppatore mobile per iOS.
I fondamentali per lo sviluppo di applicazioni multi piattaforma con Java.
Diventare degli esperti in tema di sicurezza delle applicazioni Java.
Usare Raspberry Pi e Arduino per avvicinarsi al mondo dei Maker e dell’IoT.
Le principali guide di HTML.it per diventare un esperto dei database NoSQL.
Ecco come i professionisti creano applicazioni per il Cloud con PHP.
Lo sviluppo professionale di applicazioni in PHP alla portata di tutti.
Come sviluppare applicazioni Web dinamiche con PHP e JavaScript.
Fare gli e-commerce developer con Magento, Prestashop e WooCommerce.
Realizzare applicazioni per il Web utilizzando i framework PHP.
Creare applicazioni PHP e gestire l’ambiente di sviluppo come un pro.
Percorso base per avvicinarsi al web design con un occhio al mobile.
Realizzare siti Web e Web application con WordPress a livello professionale.
Impariamo ad utilizzare Takamaka, una blockchain Java Full Stack, per scrivere codice Java installabile ed eseguibile su una blockchain
Cos’è un URL, qual è la sua funzione, come è composto: tutti i dettagli in questo approfondimento dedicato agli URL.
Come gestire i messaggi di avviso, conferma e richiesta in JavaScript
Una guida pensata per presentare le caratteristiche del framework PHP Symfony attraverso lo sviluppo di un progetto reale: la realizzazione di un social network in stile Twitter chiamato “Kwak” che significa appunto “tweet” in Islandese. L’obiettivo finale della guida è quello di proporre esempi pratici degli use case più comuni che si affrontano durante la creazione di un’applicazione.