Skip to content

Instantly share code, notes, and snippets.

@danvbe
Last active May 2, 2019 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danvbe/86b96b1c63a8668dddeb33c28dc20def to your computer and use it in GitHub Desktop.
Save danvbe/86b96b1c63a8668dddeb33c28dc20def to your computer and use it in GitHub Desktop.
A (newer) way to integrate FosUserBundle and HWIOAuthBundle - Using Symfony 3.4 with Flex

A while ago I have written a GIST on how to integrate these using Symfony 2.4. Some time have passsed and I needed to use them in a Symfony 3.4 (with Flex) ... and I had some hard times porting everything. So, in order to provide some help for you out there... here is the way I have done it:

First of all, I had some troubles installing HWIOAuthBundle. This is the solution that worked for me. On and on, you will NOT be able to install it without errors UNTIL you set up the propper configs for the bundle.

After everything was installed and running (I will not insist here on setting up FosUserBundle, as that is pretty easy and goes smoothly), we should start and setup all the proper settings.

In this demo I have used Facebook and GitHub, but you may add any other providers.

You will get some of the config automatically setup when installing bundles, but you need to focus on:

  1. .env file - here we will store the AppId and Secret for FB and Github (and any other providers you may use)
  2. hwi_oauth.yaml file, from config/packages - some configuration you will already find there after installing the bundle itself, but below you will find the complete setup for it
  3. security.yaml file, from config/packages - this is where we tell Symfony how to handle security/login, setup the firewall and secure the application a bit
  4. hwi_oauth_routing.yaml file, from config/routing - The key aspect (which gave ma a serious time wasting until figuring out) is to put the callback URLs (facebook_login and github_login) as first in the file. The other routs will already be placed there from when installing the bundle itself
  5. Register your custom FOSUBUserProvider as service - this is done in the services.yaml file from config folder
  6. Configure your User class with the appropriate data members to store the data from providers
  7. Use the links to connect - see example.twig below

Beside my original GIST and the official documentations I have used this article as inspiration. You may use it to add other providers.

### ....... ###
###> hwi/oauth-bundle ###
FB_ID=<your fb app id>
FB_SECRET=<your fb app secret>
GH_ID=<your github app id>
GH_SECRET=<your github app secret>
###< hwi/oauth-bundle ###
hwi_oauth:
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on your site, with data from the provider (facebook. google, etc.)
#and also, the connecting part (get the token and the user_id)
connect:
account_connector: app_user_provider
# list of names of the firewalls in which this bundle is active, this setting MUST be set
firewall_names: [main]
fosub:
username_iterations: 30
properties:
# these properties will be used/redefined later in the custom FOSUBUserProvider service.
facebook: facebook_id
github: github_id
# https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/2-configuring_resource_owners.md
resource_owners:
facebook:
type: facebook
client_id: '%env(FB_ID)%'
client_secret: '%env(FB_SECRET)%'
scope: "email"
options:
display: popup
csrf: true
github:
type: github
client_id: '%env(GH_ID)%'
client_secret: '%env(GH_SECRET)%'
scope: 'user:email,public_repo'
options:
csrf: true
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
login_path: /login
check_path: /login_check
oauth:
# Declare the OAuth Callback URLs for every resource owner
# They will be added in the routing.yml file too later
resource_owners:
facebook: facebook_login
github: github_login
## Provide the original login path of your application (fosuserroute)
## and the failure route when the authentication fails.
login_path: /login
failure_path: /login
# Inject a service that will be created in the step #6
oauth_user_provider:
service: app_user_provider
logout: true
anonymous: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
facebook_login:
path: /connect/check-facebook
github_login:
path: /connect/check-github
hwi_oauth_redirect:
resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /connect
hwi_oauth_connect:
resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /connect
hwi_oauth_login:
resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /login
<?php
/**
* Created by PhpStorm.
* User: ubuntu
* Date: 5/2/19
* Time: 4:45 PM
*/
namespace App\Entity;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use Symfony\Component\Security\Core\User\UserInterface;
class FOSUBUserProvider extends BaseClass
{
/**
* {@inheritDoc}
*/
public function connect(UserInterface $user, UserResponseInterface $response)
{
$property = $this->getProperty($response);
$username = $response->getUsername();
//on connect - get the access token and the user ID
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
//we "disconnect" previously connected users
if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
$previousUser->$setter_id(null);
$previousUser->$setter_token(null);
$this->userManager->updateUser($previousUser);
}
//we connect current user
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
}
/**
* {@inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$data = $response->getData();
$username = $response->getUsername();
$email = $response->getEmail() ? $response->getEmail() : $username;
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
//when the user is registrating
if (null === $user) {
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
// create new user here
$user = $this->userManager->createUser();
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
//I have set all requested data with the user's username
//modify here with relevant data
$user->setUsername($this->generateRandomUsername($username, $response->getResourceOwner()->getName()));
$user->setEmail($email);
$user->setPassword($username);
$user->setEnabled(true);
$this->userManager->updateUser($user);
return $user;
}
//if user exists - go with the HWIOAuth way
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
//update access token
$user->$setter($response->getAccessToken());
return $user;
}
/**
* Generates a random username with the given
* e.g 12345_github, 12345_facebook
*
* @param string $username
* @param string $serviceName
* @return string
*/
private function generateRandomUsername($username, $serviceName){
if(!$username){
$username = "user". uniqid((rand()), true) . $serviceName;
}
return $username. "_" . $serviceName;
}
}
### .... lot of lines are here with already existent configuration ###
app_user_provider:
class: App\Entity\FOSUBUserProvider
#this is the place where the properties are passed to the UserProvider - see hwi_oauth.yaml
arguments: ["@fos_user.user_manager",{facebook: facebook_id, github: github_id}]
<?php
/**
* Created by PhpStorm.
* User: ubuntu
* Date: 5/1/19
* Time: 11:54 PM
*/
namespace App\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/** @ORM\Column(name="facebook_id", type="string", length=255, nullable=true) */
protected $facebook_id;
/** @ORM\Column(name="facebook_access_token", type="string", length=255, nullable=true) */
protected $facebook_access_token;
/** @ORM\Column(name="github_id", type="string", length=255, nullable=true) */
protected $github_id;
/** @ORM\Column(name="github_access_token", type="string", length=255, nullable=true) */
protected $github_access_token;
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* @param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @return mixed
*/
public function getFacebookId()
{
return $this->facebook_id;
}
/**
* @param mixed $facebook_id
*/
public function setFacebookId($facebook_id)
{
$this->facebook_id = $facebook_id;
}
/**
* @return mixed
*/
public function getFacebookAccessToken()
{
return $this->facebook_access_token;
}
/**
* @param mixed $facebook_access_token
*/
public function setFacebookAccessToken($facebook_access_token)
{
$this->facebook_access_token = $facebook_access_token;
}
/**
* @return mixed
*/
public function getGithubId()
{
return $this->github_id;
}
/**
* @param mixed $github_id
*/
public function setGithubId($github_id)
{
$this->github_id = $github_id;
}
/**
* @return mixed
*/
public function getGithubAccessToken()
{
return $this->github_access_token;
}
/**
* @param mixed $github_access_token
*/
public function setGithubAccessToken($github_access_token)
{
$this->github_access_token = $github_access_token;
}
}
<a href="{{ path('hwi_oauth_service_redirect',{service: 'facebook'}) }}">
Login with Facebook
</a>
<br>
<a href="{{ path('hwi_oauth_service_redirect',{service: 'github'}) }}">
Login with Github
</a>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment