Security Setup

With FOSUserBundle setup, the only things we can't do is login and logout. FOSUserBundle does give us a /login page, but it's just a static HTML form: setting up the actual authentication part is entirely up to us. And that's why, if you try to login now, you get this angry message!

To prove how little FOSUserBundle is doing, go to /login. If you hover over your web debug toolbar, you can see that the controller behind this page is called SecurityController. Cool! In my editor, I'll find that file by filename - Shift+Shift in PHP Storm.

Sweet! See loginAction? This renders the login page. And all it does is check for any authentication errors stored in the session and render a template. It has no logic whatsoever for processing the form submit, logging in, or anything else related to security.

Configuring Logout

So let's finally add some security goodness, starting with logging out. Right now, if you go to /logout, you see an error message. This is coming from that same controller: FOSUserBundle gives us a /logout route, but its controller is never supposed to be called. To fix this, in security.yml, add logout: ~. That's it.

31 lines app/config/security.yml
... lines 1 - 2
security:
... lines 4 - 12
firewalls:
... lines 14 - 18
main:
... lines 20 - 22
logout: ~
... lines 24 - 31

Try going to /logout again. It works! We are anonymous! By adding the logout key, Symfony is now waiting for us to go to /logout. When we do, it intercepts the request and logs us out. Other than giving us the /logout route, FOSUserBundle has nothing to do with this.

Configuring form_login Security

What about logging in? It's the same thing. Under your firewall, add form_login. That's actually all you need. But, I'll add a bit more: csrf_token_generator: security.csrf.token_manager. That will make sure the CSRF token - which is already added in the FOSUserBundle login template - is verified when we submit.

31 lines app/config/security.yml
... lines 1 - 2
security:
... lines 4 - 12
firewalls:
... lines 14 - 18
main:
... lines 20 - 24
form_login:
csrf_token_generator: security.csrf.token_manager
... lines 27 - 31

As soon as we do that, go to /login and login with aquanaut1 password turtles. Winning! We are in! FOSUserBundle gives us a login form, but we need to take care of the rest... which is pretty easy.

Adding Remember Me Functionality

Oh, and on the login form, we also have a remember me checkbox. If you want this to work, you'll need to add one more setting: remember_me: with secret: '%secret%' to use the secret from parameters.yml.

34 lines app/config/security.yml
... lines 1 - 2
security:
... lines 4 - 12
firewalls:
... lines 14 - 18
main:
... lines 20 - 24
remember_me:
secret: '%secret%'
... lines 27 - 34

Ok, so about 5 lines to get our entire security system working. That kicks butt! And now, we can hook up the login link for real. Open app/Resources/views/base.html.twig and find the static link. Add an if statement: if is_granted('ROLE_USER'), then else and endif. FOSUserBundle guarantees that every user always at least has ROLE_USER. So it's safe to use this to figure out whether or not the user is logged in.

53 lines app/Resources/views/base.html.twig
<!DOCTYPE html>
<html>
... lines 3 - 13
<body>
... lines 15 - 19
<header class="header">
... lines 21 - 22
<ul class="navi">
... line 24
{% if is_granted('ROLE_USER') %}
... line 26
{% else %}
... line 28
{% endif %}
</ul>
</header>
... lines 32 - 50
</body>
</html>

For the logout link, use the route fos_user_security_logout, then we'll say "Logout". Oh, put all of this stuff inside an li tag. If you run:

53 lines app/Resources/views/base.html.twig
... lines 1 - 19
<header class="header">
... lines 21 - 22
<ul class="navi">
... line 24
{% if is_granted('ROLE_USER') %}
<li><a href="{{ path('fos_user_security_logout') }}">Logout</a></li>
... lines 27 - 28
{% endif %}
</ul>
</header>
... lines 32 - 53

php bin/console debug:router

you can see that this is one of the routes we imported. Use a similar one for login: just copy the logout line, and change it to login.

53 lines app/Resources/views/base.html.twig
... lines 1 - 19
<header class="header">
... lines 21 - 22
<ul class="navi">
... line 24
{% if is_granted('ROLE_USER') %}
... line 26
{% else %}
<li><a href="{{ path('fos_user_security_login') }}">Login</a></li>
{% endif %}
</ul>
</header>
... lines 32 - 53

Nice! Go back, and refresh. Hit Logout! Woohoo!

Next, let's see what this looks like in the database, and talk about roles.

Leave a comment!

  • 2017-05-09 Diego Aguiar

    Hey Islam Elshobokshy

    That's happening because of the last "slash" in your path, it should be "/login" (without slash)
    but if you want to avoid those problems, you can follow this guide and make a redirect to the same route without a slash
    http://symfony.com/doc/curr...

    Have a nice day!

  • 2017-05-09 Islam Elshobokshy

    No route found for "GET /login/"

    I get this error even tho I have :
    fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"