Reputation: 31
I can't seem to get Hwioauthbundle to work with my custom userbundle in symfony3. I would like to use googleoauth for my application,where a user can signin with google and also use a a registration form. Either method will store the user in the database.The registration form by itself works well but on introducing hwioauthbundle,things wouldn't work out for me. Some of the issues I've encountered include:
I've done numerous searches but I can't seem to figure out the issue. Any help with regard to where I am wrong or even alternative will be highly appreciated
providers:
intersect_provider:
entity:
class: UserBundle:User
property: username
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
guard:
authenticators:
- intersect.authenticator.form_login
entry_point: intersect.authenticator.form_login
form_login:
provider: intersect_provider
login_path: /login
check_path: /login
logout:
path: /signout
target: /
oauth:
resource_owners:
google: "/login/check-google"
login_path: /
use_forward: false
failure_path: /login
oauth_user_provider:
service: intersect.authenticator.oauth
Security.yml file
hwi_oauth:
firewall_names: [ "main" ]
resource_owners:
google:
type: google
client_id: <clientid>
client_secret: <secret>
scope: "email profile"
options:
access_type: offline
csrf: true
config.yml file
<?php
namespace Intersect\UserBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder;
use Symfony\Component\Security\Core\Security;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
private $em;
private $passwordEncoder;
private $router;
public function __construct(EntityManager $em, RouterInterface $router, UserPasswordEncoder $passwordEncoder )
{
$this->passwordEncoder = $passwordEncoder;
$this->em = $em;
$this->router = $router;
}
public function getCredentials(Request $request)
{
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
if(!$isLoginSubmit){
return;
}
$username = $request->request->get('_username');
$request->getSession()->set(Security::LAST_USERNAME, $username);
$password = $request->request->get('_password');
return [
'username'=>$username,
'password'=>$password
];
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username=$credentials['username'];
return $this->em->getRepository('UserBundle:User')->findByUsernameOrEmail($username);
}
public function checkCredentials($credentials, UserInterface $user)
{
$password=$credentials['password'];
if ($this->passwordEncoder->isPasswordValid($user, $password)) {
return true;
}
return false;
}
protected function getLoginUrl()
{
return $this->router->generate('intersect_login');
}
protected function getDefaultSuccessRedirectUrl()
{
return $this->router->generate('homepage');
}
}
My form authenticator: LoginFormAuthenticator.php
parameters:
# parameter_name: value
services:
# service_name:
# class: AppBundle\Directory\ClassName
# arguments: ["@another_service_name", "plain_value", "%parameter_name%"]
intersect.authenticator.form_login:
class: Intersect\UserBundle\Security\LoginFormAuthenticator
autowire: true
# autowire: true
hwi_oauth.user.provider.entity:
class: HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider
intersect.authenticator.oauth:
class: Intersect\UserBundle\Security\OAuthProvider
arguments:
- '@session'
- '@doctrine'
- '@service_container'
services.yml file
hwi_oauth_login:
resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /login
hwi_oauth_redirect:
resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /login
google_login:
path: /login/check-google
user:
resource: "@UserBundle/Controller/"
type: annotation
prefix: /
app:
resource: "@AppBundle/Controller/"
type: annotation
Routing.yml file
<?php
namespace Intersect\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Intersect\UserBundle\Entity\User;
class SecurityController extends Controller
{
/**
* @Route("/login",name="intersect_login")
*/
public function loginAction(){
$helper = $this->get('security.authentication_utils');
return $this->render('Intersect/login.html.twig',[
'last_username' => $helper->getLastUsername(),
'error' => $helper->getLastAuthenticationError(),
]
);
}
/**
* @Route("/signup",name="intersect_signup")
*/
public function signupAction(Request $request)
{
$user = new User;
$regform = $this->createForm('Intersect\UserBundle\Form\SignUpType', $user);
$regform->handleRequest($request);
if($regform->isSubmitted() && $regform->isValid()){
$encoder = $this->container->get('security.password_encoder');
$password = $encoder->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('homepage');
}
return $this->render('Intersect/signup.html.twig',[
'regform'=>$regform->createView()
]);
}
}
SecurityController file
<?php
namespace Intersect\UserBundle\Security;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Intersect\UserBundle\Entity\User;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Security\Core\Security;
class OAuthProvider extends OAuthUserProvider
{
protected $session, $doctrine, $admins;
public function __construct($session, $doctrine, $service_container)
{
$this->session = $session;
$this->doctrine = $doctrine;
$this->container = $service_container;
}
public function loadUserByUsername($username)
{
$qb = $this->doctrine->getManager()->createQueryBuilder();
$qb->select('u')
->from('UserBundle:User', 'u')
->where('u.googleId = :gid')
->setParameter('gid', $username)
->setMaxResults(1);
$result = $qb->getQuery()->getResult();
if (count($result)) {
return $result[0];
} else {
return new User();
}
}
public function saveOauthUserResponse(UserResponseInterface $response)
{
//data from google
$google_Id=$response->$response->getUserName();
$email=$response->getEmail();
// $username = $response->getRealName();
// $avatar = $response->getProfilePicture();
//save googele data
$this->session->set('email', $email);
$this->session->set('username', $nickname);
// $this->session->set('realname', $realname);
$qb = $this->doctrine->getManager()->createQueryBuilder();
$qb->select('u')
->from('UserBundle:User', 'u')
->where('u.oauth_Id = :gid')
->setParameter('gid', $google_Id)
->setMaxResults(1);
$result = $qb->getQuery()->getResult();
//add to database if doesn't exists
if (!count($result)) {
$user = new User();
$user->setUsername($username);
$user->setEmail($email);
$user->setoauth_Id($oauth_Id);
//$user->setRoles('ROLE_USER');
//Set some wild random pass since its irrelevant, this is Google login
// $factory = $this->container->get('security.encoder_factory');
// $encoder = $factory->getEncoder($user);
// $password = $encoder->encodePassword(md5(uniqid()), $user->getSalt());
// $user->setPassword($password);
$em = $this->doctrine->getManager();
$em->persist($user);
$em->flush();
} else {
$user = $result[0]; /* return User */
}
//set id
$this->session->set('id', $user->getId());
return $doctrine->findByUsernameOrEmail($response->getUsername());
}
}
OauthProvider. I am aware this code is not perfect, but I feel like it is not the reason why I am getting the issues mentioned earlier.
Upvotes: 2
Views: 931
Reputation: 31
I think I've solved the issues I mentioned earlier however I'm still not done with the whole thing. How I solved
I changed the hwi_oauth_login prefix to
/connect
from
/login
In Routing.yml
hwi_oauth_login:
resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /connect
Then added a forward slash to my login route in SecurityController.php
/**
* @Route("/login/",name="intersect_login")
*/
public function loginAction(){
$helper = $this->get('security.authentication_utils');
return $this->render('Intersect/signin.html.twig',[
'last_username' => $helper->getLastUsername(),
'error' => $helper->getLastAuthenticationError(),
]
);
}
The url used to start google authenication is
/connect/<\resource_owner>
where <\resource_owner> is placeholder for "google"
Now I'm getting a
You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.
error which I hope I can be able to get a solution from other threads.
Upvotes: 1