Created
February 4, 2013 09:07
-
-
Save guillaumepotier/4705757 to your computer and use it in GitHub Desktop.
Custom FB Symfony2 User Provider. Functional on Sf2.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Facebook; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\DependencyInjection\Reference; | |
use Symfony\Component\DependencyInjection\DefinitionDecorator; | |
use Symfony\Component\Config\Definition\Builder\NodeDefinition; | |
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; | |
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory; | |
/** | |
* The factory is where you hook into the security component, | |
* telling it the name of your provider and any configuration | |
* options available | |
* for it. | |
**/ | |
class FacebookFactory implements SecurityFactoryInterface | |
{ | |
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) | |
{ | |
$providerId = 'security.authentication.provider.facebook.' . $id; | |
$container->setDefinition($providerId, new DefinitionDecorator('facebook.security.authentication.provider')); | |
$listenerId = 'security.authentication.listener.facebook.' . $id; | |
$container->setDefinition($listenerId, new DefinitionDecorator('facebook.security.authentication.listener')); | |
return array($providerId, $listenerId, $defaultEntryPoint); | |
} | |
public function getPosition() | |
{ | |
return 'pre_auth'; | |
} | |
public function getKey() | |
{ | |
return 'facebook'; | |
} | |
public function addConfiguration(NodeDefinition $node) | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Facebook; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | |
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener; | |
use Symfony\Component\Security\Http\Firewall\ListenerInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
use Symfony\Component\Security\Core\SecurityContextInterface; | |
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; | |
use Symfony\Component\HttpFoundation\RedirectResponse; | |
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; | |
use Doctrine\ORM\EntityManager; | |
use Symfony\Component\Security\Core\Role\RoleInterface; | |
use Symfony\Component\Security\Core\Role\Role; | |
use Symfony\Component\HttpKernel\HttpKernelInterface; | |
use Facebook; | |
use Proj\UserBundle\Entity\User; | |
/** | |
* The listener is responsible for fielding requests to the firewall | |
* and calling the authentication provider. | |
**/ | |
class FacebookListener implements ListenerInterface | |
{ | |
protected $securityContext; | |
protected $authenticationManager; | |
protected $entityManager; | |
protected $facebookProvider; | |
private $appId; | |
private $appSecret; | |
private $facebook; | |
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, EntityManager $entityManager, FacebookProvider $facebookProvider, $appId, $appSecret) | |
{ | |
$this->securityContext = $securityContext; | |
$this->authenticationManager = $authenticationManager; | |
$this->entityManager = $entityManager; | |
$this->facebookProvider = $facebookProvider; | |
$this->appId = $appId; | |
$this->appSecret = $appSecret; | |
} | |
public function handle(GetResponseEvent $event) | |
{ | |
if (null !== $this->securityContext->getToken() || $event->getRequest()->attributes->get('_route') !== 'login') { | |
return; | |
} | |
$this->facebook = new Facebook(array( | |
'appId' => $this->appId, | |
'secret' => $this->appSecret, | |
)); | |
if ($userId = $this->facebook->getUser()) { | |
$token = $this->facebookProvider->generateToken($userId); | |
if (false === $token = $this->facebookProvider->authenticate($token, false)) { | |
$userInfo = $this->facebook->api('/' + $userId); | |
$token = $this->facebookProvider->generateToken($userId); | |
/** create new user **/ | |
$user = new User(); | |
$user->setFacebookId($userId); | |
$user->setUsername($userInfo['name']); | |
$user->setLang($userInfo['locale']); | |
$user->setEmail($userInfo['email']); | |
$this->entityManager->persist($user); | |
$this->entityManager->flush(); | |
$token->setUser($user); | |
} | |
$this->securityContext->setToken($token); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Facebook; | |
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
use Symfony\Component\Security\Core\Exception\NonceExpiredException; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Doctrine\ORM\EntityManager; | |
class FacebookProvider implements AuthenticationProviderInterface | |
{ | |
private $entityManager; | |
private $rolesRoot; | |
public function __construct(EntityManager $entityManager, $rolesRoot) | |
{ | |
$this->entityManager = $entityManager; | |
$this->rolesRoot = $rolesRoot; | |
} | |
public function authenticate(TokenInterface $token, $withHash = true) | |
{ | |
$userId = $token->getKey(); | |
$user = $this->entityManager->getRepository('UserBundle:User')->findOneBy(array('facebook_id' => $userId)); | |
if ($user) { | |
if ($withHash && $user->getUserToken() !== $token->getHash()) { | |
return false; | |
} | |
$token = $this->generateToken($userId); | |
$token->setUser($user); | |
return $token; | |
} | |
return false; | |
} | |
public function generateToken($userId) | |
{ | |
if (in_array($userId, $this->rolesRoot)) { | |
$token = new FacebookUserToken(array('ROLE_ROOT')); | |
} else { | |
$token = new FacebookUserToken(array('ROLE_USER')); | |
} | |
return $token->setKey($userId); | |
} | |
public function supports(TokenInterface $token) | |
{ | |
return $token instanceof FacebookUserToken; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Facebook; | |
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; | |
/** | |
* A token represents the user authentication data present in the request. | |
* Once a request is authenticated, the token retains the user`s data, | |
* and delivers this data across the security context. | |
**/ | |
class FacebookUserToken extends AbstractToken | |
{ | |
protected $key; | |
protected $hash; | |
public function __construct(array $roles = array()) | |
{ | |
parent::__construct($roles); | |
// If the user has roles, consider it authenticated | |
$this->setAuthenticated(count($roles) > 0); | |
} | |
public function setKey($key) | |
{ | |
$this->key = $key; | |
return $this; | |
} | |
public function getKey() | |
{ | |
return $this->key; | |
} | |
public function getAuthenticated() | |
{ | |
return $this->authenticated; | |
} | |
public function getCredentials() | |
{ | |
return ''; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Controller; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | |
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; | |
class FrontendController extends Controller | |
{ | |
/** | |
* @Route("/", name="index") | |
* @Template() | |
*/ | |
public function indexAction() | |
{ | |
return array( | |
'facebookAppId' => $this->container->getParameter('facebookAppId'), | |
'user' => null !== $this->get('security.context') ? $this->getUser() : $this->get('security.context')->getToken(), | |
); | |
} | |
/** | |
* @Route("/login", name="login") | |
*/ | |
public function login(Request $request) | |
{ | |
return $this->redirect($request->server->get('HTTP_REFERER', $this->generateUrl('index'))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Proj\UserBundle\Security; | |
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\RedirectResponse; | |
use Symfony\Component\Routing\Router; | |
use Symfony\Component\Security\Core\SecurityContext; | |
class LogoutHandler implements LogoutSuccessHandlerInterface | |
{ | |
private $router; | |
private $security; | |
public function __construct(Router $router, SecurityContext $security) | |
{ | |
$this->router = $router; | |
$this->security = $security; | |
} | |
public function onLogoutSuccess(Request $request) | |
{ | |
$this->security->setToken(null); | |
$request->getSession()->invalidate(); | |
return new RedirectResponse($request->server->get('HTTP_REFERER', $this->router->generate('index'))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?> | |
<container xmlns="http://symfony.com/schema/dic/services" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | |
<services> | |
<service id="proj.logout.handler" class="Proj\UserBundle\Security\LogoutHandler"> | |
<argument type="service" id="router" /> | |
<argument type="service" id="security.context" /> | |
</service> | |
</services> | |
</container> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
security: | |
role_hierarchy: | |
ROLE_ADMIN: ROLE_USER | |
ROLE_ROOT: ROLE_ADMIN | |
providers: | |
main: | |
entity: { class: Proj\UserBundle\Entity\User, property: username } | |
firewalls: | |
dev: | |
pattern: ^/(_(profiler|wdt)|css|images|js)/ | |
security: false | |
main: | |
pattern: ^/ | |
anonymous: true | |
facebook: ~ | |
logout: | |
path: /logout | |
target: / | |
success_handler: proj.logout.handler | |
jms_security_extra: | |
secure_all_services: false | |
expressions: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?> | |
<container xmlns="http://symfony.com/schema/dic/services" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | |
<services> | |
<service id="facebook.security.authentication.provider" class="Proj\UserBundle\Facebook\FacebookProvider"> | |
<argument type="service" id="doctrine.orm.entity_manager" /> | |
<argument>%rolesRoot%</argument> | |
</service> | |
<service id="facebook.security.authentication.listener" class="Proj\UserBundle\Facebook\FacebookListener" public="false"> | |
<argument type="service" id="security.context"/> | |
<argument type="service" id="security.authentication.manager" /> | |
<argument type="service" id="doctrine.orm.entity_manager" /> | |
<argument type="service" id="facebook.security.authentication.provider" /> | |
<argument>%facebookAppId%</argument> | |
<argument>%facebookAppSecret%</argument> | |
</service> | |
</services> | |
</container> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment