Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
TRACK

Symfony 3 >

Security Setup

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

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.

... 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.

... 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.

... 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.

<!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:

... 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.

... 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!

18
Login or Register to join the conversation
Pim W. Avatar

how to override renderLogin fucntion of fosUserBundle?
I am using symfony 4.4 and I want to pass some data to renderLogin
function. Can you please help me with this? for example, which folder
can I make a controller to extend from Securitycontroller? and do I need
to set route? if yes, how? thank you

Reply

Hi @Nauman!

In the latest FOSUserBundle, controllers are services. So to override that method, you'll need to override the class of the service. It's not a super common thing to do:

A) Create a class that extends the SecurityController
B) Create a compiler class that changes the fos_user.security.controller service to use your new class - I'd follow the 2nd example here, where you add the compiler pass to Kernel https://symfony.com/doc/current/service_container/compiler_passes.html

It will probably look something like:


    public function process(ContainerBuilder $container): void
    {
        $container->getDefinition('fos_user.security.controller')->setClass('App\\Controller\\YourNewSecurityController');
    }

Good luck!

Reply
Amina Avatar

Hey I'm using Symfony 4 , after adding the "remember_me" setting I got this error "You have requested a non-existent parameter "secret". Did you mean this: "kernel.secret"?"

Thank you !!

Reply

Hey @Amina

That's because you haven't defined any "secret" parameter, and you don't have to acutally, in Symfony4 the secret is an environment variable usually named as "APP_SECRET", and you can use it like this:


some_key: '%env(APP_SECRET)%'

Cheers!

Reply
Amina Avatar

Thank you :)

Reply
Default user avatar
Default user avatar Elmehdi GROLA | posted 4 years ago

Hello , first , I want thank you for this useful tutorial. just a remark to mention. I'm using Symfony 3.4,and in this version I think we should add the provider key in form_login ( security.yml). to let know symfony which provider to use when handling login request/action.

Reply

Hey Elmehdi GROLA

If you have a custom provider, then, yes, you have to change the config, but if not, I believe it will just fallback to FOSUserBundle user provider

Cheers!

Reply
Ravee s G. Avatar
Ravee s G. Avatar Ravee s G. | posted 4 years ago

I am using Symfony 4. My routes for login are working but I don't know why the files haven't been imported to the App folder. Now, I have to edit the files in the vendor/FOS/user-bundle folder. Is this correct or am I missing something.

Reply

Hey Ravee s G.

I don't fully get your situation. You won't get any files from the bundle except for a configuration file (and only if the bundle comes with a recipe, I think FOSUserBundle already has a recipe) inside "config/packages". Probably what you are missing is the config line that imports the routes from FOSUserBundle.

Cheers!

Reply
Ravee s G. Avatar

Hello Diego, thanks for the reply. I manually imported my twig files to templates/bundles/FOSUserBundle
This is where I copied all my folders like ChangePassword, Profile, Security, etc. from the package. It works now and I can edit those files.

Reply
Default user avatar
Default user avatar Trashcan4U | posted 5 years ago

It would be better to use {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
instead of relying on if user has ROLE_USER to figure out if user is logged in.

Reply

Hey Trashcan4U!

You're right! Well, it depends if you use the "remember_me" functionality :). If you do NOT, then it doesn't make any difference - and so we only talked about ROLE_USER to simplify things. But if you *do* use the remember me functionality, then you're 100% correct - good note!

Cheers!

Reply

btw, funny name ::p

Reply
Default user avatar
Default user avatar Szymon Chomej | posted 5 years ago

I have error when i try to log in:

No route found for "GET /" (from "http://localhost/symfony/projects/test2/web/app_dev.php/login")

...when i'm trying logout is similar.

I have this in my security.yml :
form_login: ~
logout: ~
logout:
path: fos_user_security_logout
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
csrf_token_generator: security.csrf.token_manager
remember_me:
secret: '%secret%'

Any suggestion?

Reply

Hey Szymon,

Do you have a route for "/" URL in your Symfony app? Looks like you just need to declare a route for "/" or probably clear the cache if you have a declared one. You can debug it with:

bin/console debug:router

Cheers!

1 Reply
Default user avatar
Default user avatar Szymon Chomej | Victor | posted 5 years ago

Hey Victor,

Thx for your answer.
You were right, i didnt have route "/". All my routes started with "/mojaApka/"
Now it works:).

All the best.

Reply
Default user avatar
Default user avatar Islam Elshobokshy | posted 5 years ago

No route found for "GET /login/"

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

Reply

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!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.3.*", // v3.3.18
        "doctrine/orm": "^2.5", // v2.7.0
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.5.4
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.3.0
        "sensio/distribution-bundle": "^5.0", // v5.0.18
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.25
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "knplabs/knp-markdown-bundle": "^1.4", // 1.5.1
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "friendsofsymfony/user-bundle": "^2.0" // v2.0.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.4
        "symfony/phpunit-bridge": "^3.0", // v3.2.7
        "nelmio/alice": "^2.1", // v2.3.1
        "doctrine/doctrine-fixtures-bundle": "^2.3", // v2.4.1
        "symfony/web-server-bundle": "^3.3"
    }
}
userVoice