visão global
- Introdução
- Suposições
- Configurando o pacote de usuário FOS
- Configurando FOS Facebook Bundle
Introdução
Demorei um pouco para implementar esses 3 pacotes juntos. Configurar o pacote do usuário não era o problema, mas integrar os pacotes do Facebook e do Twitter era um pé no saco. Especialmente o do Twitter, este foi um pouco obsoleto e eu precisei adicionar um setter na própria biblioteca para criar URLS de retorno de chamada dinâmico.
Este tutorial cobre os seguintes aspectos da integração:
- Criar Conta
- Conecte-se a uma conta
Suposições
Para este tutorial, presumo que você tenha configurado algumas coisas:
- Symfony 2 instalado (e totalmente executado)
- Configurar um banco de dados
- Pode executar comandos na linha de comando
- Compositor de configuração
- Você usa o Doctrine para salvar seus dados
Configurando o pacote de usuário FOS
Então, vamos começar a integração. A primeira coisa que queremos fazer é instalar o FOS Userbundle. Este pacote será nosso provedor de usuários base. É mais fácil começar com este pacote porque ele possui a maioria dos recursos que só precisam de extensão dos outros 2 pacotes.
A primeira coisa que vamos fazer é adicionar as referências do compositor:
{
"require": {
"friendsofsymfony/user-bundle": "*"
}
}
Agora execute a ferramenta composer para atualizar suas dependências e o compose fará o download da versão mais recente do pacote de usuário FOS para a pasta de fornecedores.
A próxima coisa que queremos fazer é habilitar o pacote em nosso kernel.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOSUserBundleFOSUserBundle(),
);
}
Se estiver correto, não tente ir ao site ainda, pois ainda não configuramos nosso bundle, teremos várias exceções. O que agora temos que fazer é configurar uma entidade de usuário em um pacote recém-criado. Para criar um pacote execute o comandogenerate:bundle
A entidade do usuário
Para este tutorial, vou usar o exemplo da classe de entidade do usuário do fos userbundle:
<?php
// src/My/UserBundle/Entity/User.php
namespace AcmeUserBundleEntity;
use FOSUserBundleEntityUser as BaseUser;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORMId
* @ORMColumn(type="integer")
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Como estendemos de um usuário base, já temos alguns campos definidos (funções, nome de usuário, …) então apenas adicionamos um ID à classe para salvar nosso usuário no banco de dados. Depois de fazer isso, passamos para a configuração.
Configuração
Para configurar nossa entidade, precisamos definir isso em config.yml. Abra o config.yml (em app / config / config.yml) e adicione esta configuração:
# Fos userbundle configuration.
fos_user:
db_driver: orm
firewall_name: main
user_class: MyUserBundleEntityUser
Como você pode ver em nossa configuração, precisamos adicionar um novo firewall chamado main . Para fazer isso, precisamos abrir o security.yml (app / config / security.yml).
Se você abriu este arquivo, a primeira coisa que faremos é configurar um provedor de usuário. Isso é necessário para definir a origem de nossos usuários.
Para fazer isso, adicione esse valor aos provedores:
providers:
fos_userbundle:
id: fos_user.user_provider.username
Também precisamos definir um codificador para hash nossas senhas:
encoders:
FOSUserBundleModelUserInterface: sha512
Agora que fizemos isso, podemos configurar nosso firewall real.
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /user/login
use_forward: false
check_path: /user/login_check
failure_path: null
logout:
path: /user/logout
anonymous: ~
remember_me:
key: mySuperDuperKey
lifetime: 4147200
path: /
domain: ~
Agora configuramos nosso firewall! É isso, mas ainda não estávamos prontos. No momento ainda não tínhamos regras de acesso. Então, vamos configurar esses:
access_control:
- { path: ^/user/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, role: ROLE_USER }
Nessas regras de acesso configuramos que o login deve ser aberto para usuários anônimos e que o caminho / protegido só pode ser acessado por pessoas que estão logadas. O protegido é apenas uma página padrão que você pode criar e colocar seu roteamento para esse endereço .
Bom, agora é hora de importar as rotas do pacote de usuários fos. Abra o app / routing.yml e adicione isto (pode ser que o generate: bundle já tenha adicionado este roteamento a este arquivo.):
my_user_management:
resource: "@MyUserManagementBundle/Resources/config/routing.yml"
Neste ponto, concluímos todas as etapas básicas para configurar o pacote. Agora vamos personalizar um pouco o roteamento.
Em primeiro lugar, vamos ter certeza de que nosso pacote pode herdar das fontes originais abrindo src / My / UserBundle / MyUserBundle.php. Adicione esta linha de código:
public function getParent()
{
return 'FOSUserBundle';
}
Agora crie um controlador neste pacote e nomeie-o SecurityController.
<?php
namespace MyUserBundleController;
use FOSUserBundleControllerSecurityController as BaseSecurityController;
use SymfonyComponentSecurityCoreSecurityContext;
class SecurityController extends BaseSecurityController
{
}
Depois de fazer isso, abra a pasta Resources / config e adicione ao roteamento:
fos_user_security_login:
defaults: { _controller: MyUserBundle:Security:login }
pattern: /user/login
fos_user_security_check:
pattern: /user/login_check
defaults: { _controller: MyUserBundle:Security:check }
fos_user_security_logout:
pattern: /user/logout
defaults: { _controller: MyUserBundle:Security:logout }
fos_user_profile:
resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /user
fos_user_register:
resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /registration
fos_user_resetting:
resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /account
fos_user_change_password:
resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /account
Ao fornecer os prefixos de rotas, podemos separar bem as diferentes páginas umas das outras. Você pode deixá-lo como está ou personalizá-lo de acordo com suas necessidades.
Depois de fazer isso, finalmente configuramos o pacote de usuários fos! Para testar isso, criei um usuário com acessórios . Não vou entrar em detalhes, mas aqui está um exemplo de como criar um usuário:
function load(ObjectManager $manager)
{
$userManager = $this->container->get('fos_user.user_manager');
$user1 = $userManager->createUser();
$user1->setUsername("user");
$user1->setEmail("my@email.com");
$user1->setEnabled(true);
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user1);
$encodedPass = $encoder->encodePassword('userpass', $user1->getSalt());
$user1->setPassword($encodedPass);
$userManager->updateUser($user1);
}
Configurando FOS Facebook Bundle
Agora que configuramos o pacote de usuários fos, tudo ficará mais fácil. Para instalar o pacote fos facebook vamos adicionar algumas referências no arquivo composer.json:
"facebook/php-sdk": "3.2.0",
"friendsofsymfony/facebook-bundle": "dev-master",
Depois de adicionar essas linhas, executamos o comando composer update novamente e temos nossas novas bibliotecas. A primeira coisa que vamos fazer é iniciar nossa biblioteca no kernel. Abra o app / appKernel.php e adicione esta linha:
$bundles = array(
// other bundles ...
new FOSFacebookBundleFOSFacebookBundle(),
);
Se fizermos isso, é hora de fazer algumas configurações básicas. Abra o app / config / config.yml e adicione estas linhas:
# Facebook configuration
fos_facebook:
alias: facebook
app_id: xxxxxxxxxxx
secret: xxxxxxxxxxx
cookie: true
permissions: [email, user_hometown, user_location]
Feito isso, vamos abrir o security.yml (app / config / security.yml) novamente. Como temos vários fornecedores no momento, vamos encadear esses. Para fazer isso, precisamos adicionar um provedor de cadeia e nosso provedor do Facebook:
providers:
chainprovider:
chain:
providers: [fos_userbundle, fos_facebook_provider]
fos_facebook_provider:
id: fos_facebook.user.login
Agora, no firewall principal, vamos definir nossas regras do Facebook. Nesta seção, definimos onde nosso aplicativo está localizado e também definimos nosso url de retorno de chamada aqui.
main:
fos_facebook:
app_url: "http://apps.facebook.com/this-is-my-awesome-app"
server_url: "http://mywebsite.com"
login_path: /user/login
check_path: /facebook/login_check
provider: fos_facebook_provider
default_target_path: /
A seção de firewall deve ser assim:
firewalls:
main:
pattern: ^/
fos_facebook:
app_url: "http://apps.facebook.com/this-is-my-awesome-app"
server_url: "http://mywebsite.com"
login_path: /user/login
check_path: /facebook/login_check
provider: fos_facebook_provider
default_target_path: /
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /user/login
use_forward: false
check_path: /user/login_check
failure_path: null
logout:
path: /user/logout
anonymous: ~
remember_me:
key: mySuperDuperKey
lifetime: 45146
path: /
domain: ~
Como você pode ver na seção do provedor, o provedor do Facebook fos contém um ID. Este ID faz referência a um serviço que precisamos definir. Para fazer isso (presumo que você carregue os serviços de seu pacote), abra src / My / UserBundle / Resources / config / services.yml.
Adicione estas linhas de yaml:
services:
fos_facebook.user.login:
class: MyUserBundleSecurityUserProviderFacebookProvider
arguments:
facebook: "@fos_facebook.api"
userManager: "@fos_user.user_manager"
validator: "@validator"
container: "@service_container"
Ao fazer isso, estamos definindo nosso próprio provedor do Facebook. Agora que o definimos, devemos criá-lo também! Para fazer isso, crie uma estrutura de pastas: src / MyUserBundle / Security / User / Provider e crie um arquivo php neste diretório chamado FacebookProvider. Nesta aula, vamos adicionar este código:
<?php
namespace MyUserBundleSecurityUserProvider;
use SymfonyComponentSecurityCoreExceptionUsernameNotFoundException;
use Facebook;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use BaseFacebook;
use FacebookApiException;
class FacebookProvider implements UserProviderInterface
{
/**
* @var Facebook
*/
protected $facebook;
protected $userManager;
protected $validator;
protected $container;
public function __construct(BaseFacebook $facebook, $userManager, $validator, $container)
{
$this->facebook = $facebook;
// Add this to not have the error "the ssl certificate is invalid."
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = false;
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYHOST] = 2;
$this->userManager = $userManager;
$this->validator = $validator;
$this->container = $container;
}
public function supportsClass($class)
{
return $this->userManager->supportsClass($class);
}
public function findUserByFbId($fbId)
{
return $this->userManager->findUserBy(array('facebookId' => $fbId));
}
public function findUserByUsername($username)
{
return $this->userManager->findUserBy(array('username' => $username));
}
public function connectExistingAccount()
{
try {
$fbdata = $this->facebook->api('/me');
} catch (FacebookApiException $e) {
$fbdata = null;
return false;
}
$alreadyExistingAccount = $this->findUserByFbId($fbdata['id']);
if (!empty($alreadyExistingAccount)) {
return false;
}
if (!empty($fbdata)) {
$currentUserObj = $this->container->get('security.context')->getToken()->getUser();
$user = $this->findUserByUsername($currentUserObj->getUsername());
if (empty($user)) {
return false;
}
$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);
return true;
}
return false;
}
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('');
}
if($user->getUsername() == '' || $user->getUsername() == null)
{
$user->setUsername($username . '@facebook.com');
}
$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)) {
// TODO: the user was found obviously, but doesnt match our expectations, do something smart
throw new UsernameNotFoundException('The facebook user could not be stored');
}
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