Buy

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We built a login form with a traditional route, controller and template. And so you might expect that because the form submits back to this same URL, the submit logic would live right inside this controller. Like, if the request method is POST, we would grab the email, grab the password and do some magic.

What are Authentication Listeners / Authenticators?

Well... we are not going to do that. Symfony's security works in a bit of a "magical" way, at least, it feels like magic at first. At the beginning of every request, Symfony calls a set of "authentication listeners", or "authenticators". The job of each authenticator is to look at the request to see if there is any authentication info on it - like a submitted email & password or maybe an API token that's stored on a header. If an authenticator finds some info, it then tries to use it to find the user, check the password if there is one, and log in the user! Our job is to write these authenticators.

Understanding Firewalls

Open up config/packages/security.yaml. The most important section of this file is the firewalls key. Ok, what the heck is a "firewall" in Symfony language? First, let's back up. There are two main parts of security: authentication and authorization. Authentication is all about finding out who you are and making you prove it. It's the login process. Authorization happens after authentication: it's all about determining whether or not you have access to something.

The whole job of the firewall is to authenticate you: to figure out who you are. And, it usually only makes sense to have one firewall in your app, even if you want your users to have many different ways to login - like a login form or API authentication.

But... hmm... Symfony gave us two firewalls by default! What the heck? Here's how it works: at the beginning of each request, Symfony determines the one firewall that matches the current request. It does that by comparing the URL to the regular expression pattern config. And if you look closely... the first firewall is a fake! It becomes the active firewall if the URL starts with /_profiler, /_wdt, /css, /images or /js. When this is the active firewall, it sets security to false. Basically, this firewall exists just to make sure that we don't make our site so secure that we block the web debug toolbar or some of our static assets.

In reality, we only have one real firewall called main. And because it does not have a pattern key, it will be the active firewall for all URLs, except the ones matched above. Oh, and, in case you're wondering, the names of the firewalls, dev and main are totally meaningless.

Anyways, because the job of a firewall is to authenticate the user, most of the config that goes below a firewall relates to "activating" new authentication listeners - those things that execute at the beginning of Symfony and try to log in the user. We'll add some new config here pretty soon.

Oh, and see this anonymous: true part? Keep that. This allows anonymous requests to pass through this firewall so that users can access your public pages, without needing to login. Even if you want to require authentication on every page of your site, keep this. There's a different place - access_control - where we can do this better.

Creating the Authentication with make:auth

Ok, let's get to work! To handle the login form submit, we need to create our very first authenticator. Find your terminal and run make:auth. Call the new class LoginFormAuthenticator.

Nice! This creates one new file: src/Security/LoginFormAuthenticator.php. This class is awesome: it basically has a method for each step of the authentication process. Before we walk through each one, because this authenticator will be for a login form, there's a different base class that allows us to... well... do less work!

Instead of extends AbstractGuardAuthenticator use extends AbtractFormLoginAuthenticator. I'll remove the old use statement.

Thanks to this, we no longer need onAuthenticationFailure(), start() or supportsRememberMe(): they're all handled for us. But don't worry, when we create an API token authenticator later, we will learn about these methods. We do now need one new method. Go to the Code->Generate menu, or Command + N on a Mac, and select "Implement Methods" to generate getLoginUrl().

Activating the Authenticator in security.yaml

Perfect! Unlike a lot of features in Symfony, this authenticator won't be activated automatically. To tell Symfony about it, go back to security.yaml. Under the main firewall, add a new guard key, a new authenticators key below that, and add one item in that array: App\Security\LoginFormAuthenticator.

The whole authenticator system comes from a part of the Security component called "guard", hence the name. The important part is that, as soon as we add this, at the beginning of every request, Symfony will call the supports() method on our authenticator.

To prove it, add a die statement with a message. Then, move over and, refresh! Got it! And it doesn't matter what URL we go to: the supports() method is always called at the start of the request.

And now, we're in business! Let's fill in these methods and get our user logged in.

Leave a comment!

  • 2018-09-17 weaverryan

    Hey Stéphane!

    Good question :). We change from AbstractGuardAuthenticator to AbstractFormLoginAuthenticator because, when you're building a login form, AbstractFormLoginAuthenticator requires you to do less work. If you look, AbstractFormLoginAuthenticator extends AbstractGuardAuthenticator, but it implements a few methods for you so that you don't have to. For example, when you're building a login form, we *know* that on failure, the user should be redirected to the login page. So, AbstractFormLoginAuthenticator implements the onAuthenticationError() method so that you don't have to.

    In other words, AbstractFormLoginAuthenticator is just a "helper" sub-class that allows you to do less work when you're building a login form :).

    Cheers!

  • 2018-09-15 Stéphane

    Hey Ryan,

    Thank for your reply. But why you don't use AbstractGuardAuthenticator ? It's about simplicity ?

  • 2018-09-14 weaverryan

    Hey Stéphane!

    Ah, typo! Yes, it should be AbstractGuardAuthenticator. It's not a Sf4 thing - it's just me saying the wrong class! You will see AbstractGuardAuthenticator in the video, even if I say something different in the script. Sorry for the confusion!

    Cheers!

  • 2018-09-13 Stéphane

    Hello,

    After make the command make:auth, in the LoginFormAuthenticator class extends AbstractGuardAuthenticator and no AbstractAuthenticator. This is due to the update of Sf4? Why you don't use it ?