Creating a private area with authentication in Symfony 4.3
In 9 easy steps
Post by Pedro Resende on the 20 of June of 2019 at 14:12
Tags: symfony4.3authenticationsecurityloginformprivate
Today, I've decided to take a look at Symfony 4.3 and it's login system. I must say they've made a pretty good job with the new funcionalities and the ease of use. Therefor I've decided to share with you a small tutorial on how to add a login form and a private page in easy 9 steps.
I'll assume you've already installed Symfony 4.3 and Mysql configured, if you haven't please follow check how to do it here.
Let's start by running the following command in the terminal:
./bin/console make:user
you should answer the following questions
The name of the security user class (e.g. User) [User]:
>
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
>
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
>
Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
Does this app need to hash/check user passwords? (yes/no) [yes]:
>
The newer Argon2i password hasher requires PHP 7.2, libsodium or paragonie/sodium_compat. Your system DOES support this algorithm.
You should use Argon2i unless your production system will not support it.
Use Argon2i as your password hasher (bcrypt will be used otherwise)? (yes/no) [yes]:
>
created: src/Entity/User.php
created: src/Repository/UserRepository.php
updated: src/Entity/User.php
updated: config/packages/security.yaml
Success!
Now, we have our entity created, please proceed with the migration creation and the creation of the User table in the database.
./bin/console make:migration && ./bin/console doctrine:migrations:migrate
Let's create a Guard Authenticator
./bin/console make:auth
Where you'll defined the desired options
What style of authentication do you want? [Empty authenticator]:
[0] Empty authenticator
[1] Login form authenticator
> 1
The class name of the authenticator to create (e.g. AppCustomAuthenticator):
> AppAuthenticator
Choose a name for the controller class (e.g. SecurityController) [SecurityController]:
>
created: src/Security/AppAuthenticator.php
updated: config/packages/security.yaml
created: src/Controller/SecurityController.php
created: templates/security/login.html.twig
Success!
Next:
- Customize your new authenticator.
- Finish the redirect "TODO" in the App\Security\AppAuthenticator::onAuthenticationSuccess() method.
- Review & adapt the login template: templates/security/login.html.twig.
Now, we need a registration for to add the users to the database, we'll execute the following command for that
./bin/console make:registration-form
Creating a registration form for App\Entity\User
Do you want to add a @UniqueEntity validation annotation on your User class to make sure duplicate accounts aren't created? (yes/no) [yes]:
>
Do you want to automatically authenticate the user after registration? (yes/no) [yes]:
>
updated: src/Entity/User.php
created: src/Form/RegistrationFormType.php
created: src/Controller/RegistrationController.php
created: templates/registration/register.html.twig
Success!
Next: Go to /register to check out your new form!
Make any changes you need to the form, controller & template.
Now, edit the file src/Controller/SecurityController.php and add the following
/**
* @Route("/logout", name="app_logout", methods={"GET"})
*/
public function logout()
{
// controller can be blank: it will never be executed!
throw new \Exception('Don\'t forget to activate logout in security.yaml');
}
This will allow the users to logout.
Now, in the security.yml we need to define that the app_logout path is responsible for the users logout
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
logout:
path: app_logout
Let's update the login reddirect path by changing in the file, where you have
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
// For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
}
By
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('default'));
}
Finally, create the following controller symfony/src/Controller/DefaultController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class DefaultController extends AbstractController
{
/**
* @Route("/", name="default")
*/
public function index()
{
return $this->render('default/index.html.twig', [
'controller_name' => 'DefaultController',
]);
}
/**
* @Route("/private", name="private")
*/
public function private()
{
$this->denyAccessUnlessGranted('ROLE_USER');
return $this->render('default/index.html.twig', [
'controller_name' => 'DefaultController',
]);
}
}
Now, all you have to do is register a new user, by accessing to the path /register and to login, use the path /login.
P.S. - Please let me know if you have a easier and cleaner way, without bundles.