This gist is an opiniated version of a simple user registration, login, password resetting workflow, that takes a couple of minutes to setup and just works.
This is php7.x compatible only (because you should probably be using it anyway), and if you insiste on having php5.x just remove the annotations in the User.php
entity file.
Everything is available in the security page in the Symfony documentation:
https://symfony.com/doc/3.4/security.html
-
-
Save Nugjii/35246d25b79cefaf0c5641d2bfe39f6c to your computer and use it in GitHub Desktop.
A simple User authentication setup to copy & paste into your Symfony 3.4 install
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
{% extends 'base.html.twig' %} | |
{% block body %} | |
{{ form(form) }} | |
{% endblock %} |
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 AppBundle\Form; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\Extension\Core\Type\PasswordType; | |
use Symfony\Component\Form\Extension\Core\Type\RepeatedType; | |
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
class NewPasswordType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('password', RepeatedType::class, ['type' => PasswordType::class]) | |
->add('submit', SubmitType::class); | |
} | |
} |
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 AppBundle\Form; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\Extension\Core\Type\EmailType; | |
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
class PasswordRequestType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('email', EmailType::class) | |
->add('send', SubmitType::class); | |
} | |
} |
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
{% extends 'base.html.twig' %} | |
{% block body %} | |
<p>Register here</p> | |
{{ form(form) }} | |
{% endblock %} |
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 AppBundle\Controller; | |
use AppBundle\Entity\User; | |
use AppBundle\Form\RegistrationFormType; | |
use Doctrine\ORM\EntityManagerInterface; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |
use Symfony\Component\Routing\Annotation\Route; | |
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | |
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; | |
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |
class RegistrationController extends Controller | |
{ | |
/** | |
* @Route("/register", name="register", methods={"GET", "POST"}) | |
*/ | |
public function register( | |
Request $request, | |
UserPasswordEncoderInterface $encoder, | |
TokenStorageInterface $tokenStorage, | |
EntityManagerInterface $entityManager, | |
SessionInterface $session | |
) { | |
$user = new User(); | |
$form = $this->createForm(RegistrationFormType::class, $user); | |
$form->handleRequest($request); | |
if ($form->isSubmitted() && $form->isValid()) { | |
$password = $encoder->encodePassword($user, $user->getPlainPassword()); | |
$user->setPassword($password); | |
$entityManager->persist($user); | |
$entityManager->flush(); | |
$this->addFlash('success', "Your accound was created"); | |
$token = new UsernamePasswordToken($user, $password, 'main'); | |
$tokenStorage->setToken($token); | |
$session->set('_security_main', serialize($token)); | |
return $this->redirectToRoute('homepage'); | |
} | |
return $this->render( | |
'register.html.twig', | |
[ | |
'form' => $form->createView(), | |
] | |
); | |
} | |
} |
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
{% extends 'base.html.twig' %} | |
{% block body %} | |
<p>Please enter a new password.</p> | |
{{ form(form) }} | |
{% endblock %} |
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
{% extends 'base.html.twig' %} | |
{% block body %} | |
<p>We will send a resetting link to your account email.</p> | |
{{ form(form) }} | |
{% endblock %} |
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 AppBundle\Controller; | |
use AppBundle\Entity\User; | |
use AppBundle\Form\NewPasswordType; | |
use AppBundle\Form\PasswordRequestType; | |
use Doctrine\ORM\EntityManagerInterface; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |
use Symfony\Component\Routing\Annotation\Route; | |
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | |
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; | |
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |
class ResettingController extends Controller | |
{ | |
/** | |
* @Route("/reset_password", name="reset_password", methods={"GET", "POST"}) | |
*/ | |
public function resetPassword( | |
Request $request, | |
EntityManagerInterface $entityManager | |
) { | |
$form = $this->createForm(PasswordRequestType::class); | |
$form->handleRequest($request); | |
if ($form->isSubmitted() && $form->isValid()) { | |
$email = $form->get('email')->getData(); | |
$token = bin2hex(random_bytes(32)); | |
$user = $entityManager->getRepository(User::class)->findOneBy(['email' => $email]); | |
if ($user instanceof User) { | |
$user->setPasswordRequestToken($token); | |
$entityManager->flush(); | |
// send your email with SwiftMailer or anything else here | |
$this->addFlash('success', "An email has been sent to your address"); | |
return $this->redirectToRoute('reset_password'); | |
} | |
} | |
return $this->render('reset-password.html.twig', ['form' => $form->createView()]); | |
} | |
/** | |
* @Route("/reset_password/confirm/{token}", name="reset_password_confirm", methods={"GET", "POST"}) | |
*/ | |
public function resetPasswordCheck( | |
Request $request, | |
string $token, | |
EntityManagerInterface $entityManager, | |
UserPasswordEncoderInterface $encoder, | |
TokenStorageInterface $tokenStorage, | |
SessionInterface $session | |
) { | |
$user = $entityManager->getRepository(User::class)->findOneBy(['passwordRequestToken' => $token]); | |
if (!$token || !$user instanceof User) { | |
$this->addFlash('danger', "User not found"); | |
return $this->redirectToRoute('reset_password'); | |
} | |
$form = $this->createForm(NewPasswordType::class); | |
$form->handleRequest($request); | |
if ($form->isSubmitted() && $form->isValid()) { | |
$plainPassword = $form->get('password')->getData(); | |
$password = $encoder->encodePassword($user, $plainPassword); | |
$user->setPassword($password); | |
$user->setPasswordRequestToken(null); | |
$entityManager->flush(); | |
$token = new UsernamePasswordToken($user, $password, 'main'); | |
$tokenStorage->setToken($token); | |
$session->set('_security_main', serialize($token)); | |
$this->addFlash('success', "Your new password has been set"); | |
return $this->redirectToRoute('homepage'); | |
} | |
return $this->render('reset-password-confirm.html.twig', ['form' => $form->createView()]); | |
} | |
} |
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: | |
encoders: | |
AppBundle\Entity\User: | |
algorithm: bcrypt | |
providers: | |
app_users: | |
entity: { class: AppBundle\Entity\User, property: email } | |
role_hierarchy: | |
ROLE_ADMIN: ROLE_USER | |
firewalls: | |
dev: | |
pattern: ^/(_(profiler|wdt|error)|css|images|js)/ | |
security: false | |
main: | |
pattern: ^/ | |
form_login: | |
provider: app_users | |
login_path: login | |
check_path: login | |
logout: | |
path: /logout | |
target: / | |
anonymous: true | |
access_control: | |
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/reset_password, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/, role: ROLE_USER } |
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 AppBundle\Controller; | |
use AppBundle\Form\UserLoginType; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Symfony\Component\Routing\Annotation\Route; | |
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; | |
class SecurityController extends Controller | |
{ | |
/** | |
* @Route("/login", name="login", methods={"GET", "POST"}) | |
*/ | |
public function login(AuthenticationUtils $authenticationUtils) | |
{ | |
$error = $authenticationUtils->getLastAuthenticationError(); | |
$lastUsername = $authenticationUtils->getLastUsername(); | |
$form = $this->createForm(UserLoginType::class); | |
return $this->render( | |
'login.html.twig', | |
[ | |
'form' => $form->createView(), | |
'last_username' => $lastUsername, | |
'error' => $error, | |
] | |
); | |
} | |
} |
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 AppBundle\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
/** | |
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository") | |
* @ORM\Table(name="app_user") | |
* @UniqueEntity("email") | |
*/ | |
class User implements UserInterface | |
{ | |
/** | |
* @ORM\Id | |
* @ORM\Column(type="integer") | |
* @ORM\GeneratedValue(strategy="AUTO") | |
*/ | |
protected $id; | |
/** | |
* @var string | |
* | |
* @ORM\Column(type="string", length=180, unique=true) | |
*/ | |
protected $email; | |
/** | |
* @var string | |
* | |
* @ORM\Column(name="password", type="string", length=100) | |
*/ | |
protected $password; | |
/** | |
* @var string|null | |
*/ | |
protected $plainPassword; | |
/** | |
* @var string|null | |
* | |
* @ORM\Column(type="string", length=255, nullable=true) | |
*/ | |
protected $passwordRequestToken; | |
/** | |
* @var array $roles | |
* | |
* @ORM\Column(type="array") | |
*/ | |
private $roles = ['ROLE_USER']; | |
/** | |
* @return mixed | |
*/ | |
public function getId() | |
{ | |
return $this->id; | |
} | |
/** | |
* @return string | |
*/ | |
public function getEmail(): string | |
{ | |
return $this->email; | |
} | |
/** | |
* @param string $email | |
* | |
* @return User | |
*/ | |
public function setEmail(string $email): User | |
{ | |
$this->email = $email; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getPassword(): string | |
{ | |
return $this->password; | |
} | |
/** | |
* @param string $password | |
* | |
* @return User | |
*/ | |
public function setPassword(string $password): User | |
{ | |
$this->password = $password; | |
return $this; | |
} | |
/** | |
* @return null|string | |
*/ | |
public function getPlainPassword(): ?string | |
{ | |
return $this->plainPassword; | |
} | |
/** | |
* @param null|string $plainPassword | |
* | |
* @return User | |
*/ | |
public function setPlainPassword(?string $plainPassword): User | |
{ | |
$this->plainPassword = $plainPassword; | |
return $this; | |
} | |
/** | |
* @return null|string | |
*/ | |
public function getPasswordRequestToken(): ?string | |
{ | |
return $this->passwordRequestToken; | |
} | |
/** | |
* @param null|string $passwordRequestToken | |
* | |
* @return User | |
*/ | |
public function setPasswordRequestToken(?string $passwordRequestToken): User | |
{ | |
$this->passwordRequestToken = $passwordRequestToken; | |
return $this; | |
} | |
/** | |
* @return array | |
*/ | |
public function getRoles(): array | |
{ | |
return $this->roles; | |
} | |
/** | |
* @param array $roles | |
* | |
* @return User | |
*/ | |
public function setRoles(array $roles): User | |
{ | |
$this->roles = $roles; | |
return $this; | |
} | |
/** | |
* @return string|null The salt | |
*/ | |
public function getSalt() | |
{ | |
return null; | |
} | |
/** | |
* @return string The username | |
*/ | |
public function getUsername(): string | |
{ | |
return $this->email; | |
} | |
/** | |
* Removes sensitive data from the user. | |
*/ | |
public function eraseCredentials(): void | |
{ | |
$this->plainPassword = null; | |
} | |
} |
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 AppBundle\Form; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\Extension\Core\Type\PasswordType; | |
use Symfony\Component\Form\Extension\Core\Type\SubmitType; | |
use Symfony\Component\Form\Extension\Core\Type\TextType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
class UserLoginType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('_username', TextType::class) | |
->add('_password', PasswordType::class) | |
->add('submit', SubmitType::class); | |
} | |
public function getBlockPrefix() | |
{ | |
return null; | |
} | |
} |
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 AppBundle\Form; | |
use AppBundle\Entity\User; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\Extension\Core\Type\EmailType; | |
use Symfony\Component\Form\Extension\Core\Type\PasswordType; | |
use Symfony\Component\Form\Extension\Core\Type\RepeatedType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
class UserRegistrationType extends AbstractType | |
{ | |
/** | |
* {@inheritdoc} | |
*/ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('email', EmailType::class) | |
->add('plainPassword', RepeatedType::class, ['type' => PasswordType::class]) | |
->add('submit', SubmitType::class); | |
} | |
/** | |
* @param OptionsResolver $resolver | |
*/ | |
public function configureOptions(OptionsResolver $resolver) | |
{ | |
$resolver->setDefaults(['data_class' => User::class]); | |
} | |
public function getBlockPrefix() | |
{ | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment