gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
There are two steps to building a login form: the visual part - the HTML form itself - and the logic when you submit that form: finding the user, checking the password, and logging in. The interesting part is... if you think about it, the first part - the HTML form - has absolutely nothing to do with security. It's just... well... a boring, normal HTML form!
Let's get that built first. By the way, there are plans to add a make
command to generate a login form and the security logic automatically, so that we only need to fill in a few details. That doesn't exist yet, so.. we'll do it manually. But, that's a bit better for learning anyways.
To build the controller, let's at least use one shortcut. At your terminal, run:
php bin/console make:controller
to create a new class called SecurityController
. Move over and open that:
... lines 1 - 2 | |
namespace App\Controller; | |
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |
use Symfony\Component\Routing\Annotation\Route; | |
class SecurityController extends AbstractController | |
{ | |
/** | |
* @Route("/security", name="security") | |
*/ | |
public function index() | |
{ | |
return $this->render('security/index.html.twig', [ | |
'controller_name' => 'SecurityController', | |
]); | |
} | |
} |
Ok: update the URL to /login
, change the route name to app_login
and the method to login()
:
... lines 1 - 7 | |
class SecurityController extends AbstractController | |
{ | |
/** | |
* @Route("/login", name="app_login") | |
*/ | |
public function login() | |
{ | |
... lines 15 - 17 | |
} | |
} |
We don't need to pass any variables yet, and we'll call the template login.html.twig
:
... lines 1 - 7 | |
class SecurityController extends AbstractController | |
{ | |
... lines 10 - 12 | |
public function login() | |
{ | |
return $this->render('security/login.html.twig', [ | |
]); | |
} | |
} |
Next, down in templates/security
, rename index.html.twig
to login.html.twig
. Let's try it! Move over, go to /login
and... whoops!
Variable
controller_name
does not exist.
Duh! I removed the variables that we were passing into the template:
... lines 1 - 7 | |
class SecurityController extends AbstractController | |
{ | |
... lines 10 - 12 | |
public function login() | |
{ | |
return $this->render('security/login.html.twig', [ | |
]); | |
} | |
} |
Empty all of the existing code from the template. Then, change the title to Login!
and, for now, just add an h1
with "Login to the SpaceBar!":
{% extends 'base.html.twig' %} | |
{% block title %}Login!{% endblock %} | |
{% block body %} | |
<h1>Login to the SpaceBar!</h1> | |
{% endblock %} |
Try it again: perfect! Well, not perfect - it looks terrible... and there's no login form yet. To fix that part, Google for "Symfony login form" to find a page on the Symfony docs that talks all about this. We're coming here so that we can steal some code!
Scroll down a bit until you see a login()
method that has some logic in it. Copy the body, move back to our controller, and paste!
... lines 1 - 8 | |
class SecurityController extends AbstractController | |
{ | |
... lines 11 - 13 | |
public function login(AuthenticationUtils $authenticationUtils) | |
{ | |
// get the login error if there is one | |
$error = $authenticationUtils->getLastAuthenticationError(); | |
// last username entered by the user | |
$lastUsername = $authenticationUtils->getLastUsername(); | |
... lines 21 - 25 | |
} | |
} |
This needs an AuthenticationUtils
class as an argument. Add it: AuthenticationUtils $authenticationUtils
:
... lines 1 - 6 | |
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; | |
class SecurityController extends AbstractController | |
{ | |
... lines 11 - 13 | |
public function login(AuthenticationUtils $authenticationUtils) | |
{ | |
... lines 16 - 25 | |
} | |
} |
Then, these two new variables are passed into Twig. Copy them, and also paste it:
... lines 1 - 8 | |
class SecurityController extends AbstractController | |
{ | |
... lines 11 - 13 | |
public function login(AuthenticationUtils $authenticationUtils) | |
{ | |
... lines 16 - 21 | |
return $this->render('security/login.html.twig', [ | |
'last_username' => $lastUsername, | |
'error' => $error, | |
]); | |
} | |
} |
In a few minutes, we're going to talk about where these two variables are set. They both deal with authentication.
But first, go back to the docs and find the login form. Copy this, move over and paste it into our body:
... lines 1 - 4 | |
{% block body %} | |
<h1>Login to the SpaceBar!</h1> | |
{% if error %} | |
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div> | |
{% endif %} | |
<form action="{{ path('login') }}" method="post"> | |
<label for="username">Username:</label> | |
<input type="text" id="username" name="_username" value="{{ last_username }}" /> | |
<label for="password">Password:</label> | |
<input type="password" id="password" name="_password" /> | |
{# | |
If you want to control the URL the user | |
is redirected to on success (more details below) | |
<input type="hidden" name="_target_path" value="/account" /> | |
#} | |
<button type="submit">login</button> | |
</form> | |
{% endblock %} |
Notice: there is nothing special about this form: it has a username field, a password field and a submit button. And, we're going to customize it, so don't look too closely yet.
Move back to your browser to check things out. Bah!
Unable to generate a URL for the named route "login"
This comes from login.html.twig
. Of course! The template we copied is pointing to a route called login
, but our route is called app_login
:
... lines 1 - 8 | |
class SecurityController extends AbstractController | |
{ | |
/** | |
* @Route("/login", name="app_login") | |
*/ | |
public function login(AuthenticationUtils $authenticationUtils) | |
{ | |
... lines 16 - 25 | |
} | |
} |
Actually, just remove the action=
entirely:
... lines 1 - 4 | |
{% block body %} | |
... lines 6 - 11 | |
<form method="post"> | |
... lines 13 - 25 | |
</form> | |
{% endblock %} |
If a form doesn't have an action
attribute, it will submit right back to the same URL - /login
- which is what I want anyways.
Refresh again. Perfect! Well, it still looks awful. Oof. To fix that, I'm going to replace the HTML form with some markup that looks nice in Bootstrap 4 - you can copy this from the code block on this page:
... lines 1 - 10 | |
{% block body %} | |
<form class="form-signin" method="post"> | |
{% if error %} | |
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div> | |
{% endif %} | |
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1> | |
<label for="inputEmail" class="sr-only">Email address</label> | |
<input type="email" name="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus> | |
<label for="inputPassword" class="sr-only">Password</label> | |
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required> | |
<div class="checkbox mb-3"> | |
<label> | |
<input type="checkbox" value="remember-me"> Remember me | |
</label> | |
</div> | |
<button class="btn btn-lg btn-primary btn-block" type="submit"> | |
Sign in | |
</button> | |
</form> | |
{% endblock %} |
Before we look at this new code, try it! Refresh! Still ugly! Dang! Oh yea, that's because we need to include a new CSS file for this markup.
If you downloaded the course code, you should have a tutorial/
directory with two CSS files inside. Copy login.css
, find your public/
directory and paste the file into public/css
:
body { | |
background-color: #fff; | |
} | |
.form-signin { | |
width: 100%; | |
max-width: 330px; | |
padding: 15px; | |
margin: auto; | |
margin-top: 50px; | |
} | |
.form-signin .checkbox { | |
font-weight: 400; | |
} | |
.form-signin .form-control { | |
position: relative; | |
box-sizing: border-box; | |
height: auto; | |
padding: 10px; | |
font-size: 16px; | |
} | |
.form-signin .form-control:focus { | |
z-index: 2; | |
} | |
.form-signin input[type="email"] { | |
margin-bottom: -1px; | |
border-bottom-right-radius: 0; | |
border-bottom-left-radius: 0; | |
} | |
.form-signin input[type="password"] { | |
margin-bottom: 10px; | |
border-top-left-radius: 0; | |
border-top-right-radius: 0; | |
} |
So far in this series, we are not using Webpack Encore, which is an awesome tool for professionally combining and loading CSS and JS files. Instead, we're just putting CSS files into the public/
directory and pointing to them directly. If you want to learn more about Encore, go check out our Webpack Encore tutorial.
Anyways, we need to add a link
tag for this new CSS file... but I only want to include it on this page, not on every page - we just don't need the CSS on every page. Look at base.html.twig
:
<html lang="en"> | |
<head> | |
... lines 5 - 8 | |
{% block stylesheets %} | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> | |
<link rel="stylesheet" href="{{ asset('css/font-awesome.css') }}"> | |
<link rel="stylesheet" href="{{ asset('css/styles.css') }}"> | |
{% endblock %} | |
</head> | |
... lines 15 - 66 | |
</body> | |
</html> |
We're including three CSS files in the base layout. Ah, and they all live inside a block called stylesheets
.
We basically want to add a fourth link
tag right below these... but only on the login page. To do that, in login.html.twig
, add block stylesheets
and endblock
:
... lines 1 - 4 | |
{% block stylesheets %} | |
... lines 6 - 8 | |
{% endblock %} | |
... lines 10 - 32 |
This will override that block completely... which is actually not exactly what we want. Nope, we want to add to that block. To do that print parent()
:
... lines 1 - 4 | |
{% block stylesheets %} | |
{{ parent() }} | |
... lines 7 - 8 | |
{% endblock %} | |
... lines 10 - 32 |
This will print the content of the parent block - the 3 link tags - and then we can add the new link tag below: link
, with href=
and login.css
. PhpStorm helps fill in the asset()
function:
... lines 1 - 4 | |
{% block stylesheets %} | |
{{ parent() }} | |
<link rel="stylesheet" href="{{ asset('css/login.css') }}"> | |
{% endblock %} | |
... lines 10 - 32 |
Now it should look good. Try it. Boom! Oh, but we don't need that h1
tag anymore.
So even though this looks much better, it's still just a very boring HTML form. It has an email field and a password field... though, we won't add the password-checking logic until later. It also has a "remember me" checkbox that we'll learn how to activate.
The point is: you can make your login form look however you want. The only special part is this error
variable, which, when we're done, will be the authentication error if the user just entered a bad email or password:
... lines 1 - 10 | |
{% block body %} | |
<form class="form-signin" method="post"> | |
{% if error %} | |
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div> | |
{% endif %} | |
... lines 16 - 29 | |
</form> | |
{% endblock %} |
I'll plan ahead and add a Bootstrap class for this:
... lines 1 - 10 | |
{% block body %} | |
<form class="form-signin" method="post"> | |
{% if error %} | |
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div> | |
{% endif %} | |
... lines 16 - 29 | |
</form> | |
{% endblock %} |
Ok. Login form is done! But... we probably need a link to this page. In the upper right corner, we have a cute user dropdown... which is totally hardcoded with fake data. Go back to base.html.twig
and scroll down to find this. There it is! For now, let's comment-out that drop-down:
<html lang="en"> | |
... lines 3 - 15 | |
<body> | |
<nav class="navbar navbar-expand-lg navbar-dark navbar-bg mb-5"> | |
... lines 18 - 21 | |
<div class="collapse navbar-collapse" id="navbarNavDropdown"> | |
... lines 23 - 34 | |
<ul class="navbar-nav ml-auto"> | |
... lines 36 - 38 | |
{# | |
<li class="nav-item dropdown" style="margin-right: 75px;"> | |
<a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
<img class="nav-profile-img rounded-circle" src="{{ asset('images/astronaut-profile.png') }}"> | |
</a> | |
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> | |
<a class="dropdown-item" href="#">Profile</a> | |
<a class="dropdown-item" href="#">Create Post</a> | |
<a class="dropdown-item" href="#">Logout</a> | |
</div> | |
</li> | |
#} | |
</ul> | |
</div> | |
</nav> | |
... lines 54 - 71 | |
</body> | |
</html> |
We'll re-add it later when we have real data. Then, copy a link from above, paste ithere and change it to Login with a link to app_login
:
<html lang="en"> | |
... lines 3 - 15 | |
<body> | |
<nav class="navbar navbar-expand-lg navbar-dark navbar-bg mb-5"> | |
... lines 18 - 21 | |
<div class="collapse navbar-collapse" id="navbarNavDropdown"> | |
... lines 23 - 34 | |
<ul class="navbar-nav ml-auto"> | |
<li class="nav-item"> | |
<a style="color: #fff;" class="nav-link" href="{{ path('app_login') }}">Login</a> | |
</li> | |
{# | |
<li class="nav-item dropdown" style="margin-right: 75px;"> | |
<a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
<img class="nav-profile-img rounded-circle" src="{{ asset('images/astronaut-profile.png') }}"> | |
</a> | |
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> | |
<a class="dropdown-item" href="#">Profile</a> | |
<a class="dropdown-item" href="#">Create Post</a> | |
<a class="dropdown-item" href="#">Logout</a> | |
</div> | |
</li> | |
#} | |
</ul> | |
</div> | |
</nav> | |
... lines 54 - 71 | |
</body> | |
</html> |
Try it - refresh! We got it! HTML login form, check! We are now ready to fill in the logic of what happens when we submit the form. We'll do that in something called an "authenticator".
Hey Metin Ö.
I guess the easiest way is to use "LogoutEvent" or "logout success handler" depending on symfony version. You can read more here https://symfony.com/doc/cur...
Cheers!
Hi, I created a login form almost exactly as in this tutorial. Works great. Now I need to have a separate LoginFormAuthenticator that grabs the user input and validates against an Ldap server, sort of an employee login with the goal being to skip the whole registration process allowing employees to use their active directory creds to authenticate. I installed the Ldap package, added a service, a separate user provider, firewall, routes and login form. Also, this application uses EasyAdmin, fyi. Is this possible to have two separate logins for authentication processed in the same application? So far, submitting the 'employee' login form doesn't submit any form data to anywhere that I can tell. Tried using http_basic_ldap and there seemed to be session conflicts between the two types of users, not exactly sure? Am I going about this from the wrong angle? I know it's a lot I really appreciate any help/suggestions.
Hey Brent!
Ah, sounds cool! Here are some pointers :).
> installed the Ldap package, added a service, a separate user provider, firewall, routes and login form
All good... maybe :). You may not need 2 separate firewalls. It depends on your app: will "normal users" and "ldap users" being viewing the same pages? My guess is "yes". In that case, you only want 1 firewall (only 1 firewall can be active per request, and the active one is chosen by matching a URL to the firewall's pattern, so if you have 2 firewalls, only 1 will be active for a specific page that both users need to go to). Anyways, this is 100% ok to do this - it just means that you have 2 different ways to log into the same security system (i.e. firewall).
> So far, submitting the 'employee' login form doesn't submit any form data to anywhere that I can tell.
I would probably create a custom authenticator for the Ldap authentication. Here's the idea:
* /login is your normal login form. It submits to /login/check (the URLs may not match, I'm just showing an example) and your "login form authenticator" knows to "support" and "act" on this URL.
* /login/employees is your employee login form. It submits to /login/employees/check and your "ldap login form authenticator" knows to support and act on this URL. Inside of this authenticator, you could use an Ldap service that you registered (if you follow the LDAP Symfony docs, registering a service is one of the steps) to find the user information in LDAP. Then you would return a User object (more on this User object below).
You could absolutely also use http_basic_ldap or even form_login_ldap - that gives you more functionality out of the box, I just find them a lot more magic (who is reading my credentials and what does the lookup look like?).
One last point: there is a question of should have have just 1 User class or 2 User classes. Having 2 can complicate things because wherever you have $this->getUser() in your app, you may be getting UserClass1 or UserClass2, and each may have different methods/properties. It depends on your app, but I typically prefer to have just 1 User class, which would be an entity in your case. If you do this, then your "ldap form login authenticator" would do this:
A) Fetch the info from the ldap server
B) Check the database to see if that User is in the database yet (this will make more sense in a second). If it is, just return it (maybe you update some data on it from LDAP if you want).
C) If the user doesn't exist yet, create it, set some data on it and persist/flush to the database. You might even set some custom roles - e.g. ROLE_HUMAN_RESOURCES - based on the permissions that user has in LDAP.
Let me know if this helps!
Cheers!
How is the user input on the login form (twig template) validated? If the user input is grabbed by an LoginFormAuthenticator which searches for an user by using a UserProvider, it's essential that the UserProvider doesn't allow SQL injections. Wouldn't it be better to validate the input via FormBuilder instead of using a Twig templalte without validation?
Hey Nino!
Sorry for my slow reply! Excellent question :).
> If the user input is grabbed by an LoginFormAuthenticator which searches for an user by using a UserProvider, it's essential that the UserProvider doesn't allow SQL injections
You're 100% correct. And the UserProvider (the Doctrine user provider) DOES protect against SQL injections by using the normal prepared statement queries. So, you're covered without thinking about it :). This is actually the same reason that you don't have to worry about SQL injections with forms. The form system will help validate "invalid" input (e.g. putting a string into a number field, hacking a choice element to add an option that doesn't exist, or any of your @Assert\ rules), but the form system in itself doesn't validate against SQL injections. The reason is that... it doesn't need to. When you use the ORM (i.e. when you're querying through your repository [as long as you're using :wildcards and setParameter() in your custom queries] and saving entity objects, everything uses prepared statements).
Let me know if that makes sense!
Cheers!
Why It's recommended to implement a basic form login, instead of using the formbuilder and render the form via {{form(form)}} etc ??
Hey ahmedbhs
That's a good question and the answer is because of a couple of reasons. First, the error messages come from a different part of the framework (Security component), so you can't just execute {{ form_error(form.email) }}
Second, you have to change the name of the CSRF token
and lastly because you may not be using the Form component in your application.
Cheers!
Twig grabs the error from the form field which is set after validating the form itself. But, the login action is different, it's intercepted by Symfony. In other to access to the error message, you have to retrieve by calling Symfony\Component\Security\Http\Authentication\AuthenticationUtils::getLastAuthenticationError()
About the CSRF, you don't have to actually change the token but you have to use the same name you used for generating it when check if it's valid in the LoginFormAuthenticator
Could we simply use bootstrap4 form theme here ?
# config/packages/twig.yaml
twig:
form_themes: ['bootstrap_4_layout.html.twig']
Hey Kaizoku,
Yes, you can! But unless you write form's HTML code yourself like we did in this screencast. But if you use Symfony Forms - just specify "form_themes" and Twig will automatically style your form with Bootstrap 4 theme - that's the power of Symfony Form component and its Twig integration :)
Cheers!
Hey Kamil,
Hm, try to clear the cache first - does it help? If no, try to debug your routes with the next command:
$ bin/console debug:router
You can even grep by "login" if needed:
$ bin/console debug:router | grep login
Do you see the login route in the output?
Cheers!
Hey Kamil,
If you're about clearing the cache - yeah, most of the time you don't need to do it when you're in dev env... but depending on whether you use virtualization tool e.g. Docker or no it might be a good idea to start with clearing the cache before thinking about something else :)
Cheers!
Hi! I'm following this tutorial for my project but after I created the SecurityController all my pages doesn't work anymore. Here is the log:
(5/5) RuntimeError
An exception has been thrown during the rendering of a template ("[Syntax Error] Expected PlainValue, got ''' at position 22 in method App\Controller\SecurityController::login() in C:\Users\Giaco\Desktop\TribunaleMinori\TribunaleMinori\config/routes\../../src/Controller/ (which is being imported from "C:\Users\Giaco\Desktop\TribunaleMinori\TribunaleMinori\config/routes/annotations.yaml"). Make sure annotations are installed and enabled.").
And this happen with every page not only with the /login page, can you help me?
Hey Gballocc7
I've seen only that error when you try to use single quotes on annotations, i.e
/**
* @Route('/path')
*/
public function action(){...}
Can you double check that and let me know if that was the case?
Cheers!
Hey Dinu B.!
Yea, I added the fancier version of make:auth to MakerBundle shortly after releasing this tutorial :). But basically, what we are writing by hand in this tutorial is more or less identical to what you can now get from make:auth by select the "form login" option. So, you can simple use that to generate all of this code. Or, you can follow this tutorial if you want to learn a bit more about what that generated code does and how it works :).
Let me know if that makes sense!
Cheers!
thx for reply. U're right regarding make:auth, I wrote that when I was watching that episode and right after that things started to clarify. My coding style it's kinda old school but symfony changed my opinion. Keep doing what u're doing!
Ha! Awesome! Well, you did it the hard way... I mean the *right* way then - you coded up everything manually, which is the best way to master this stuff in my opinion. Keep up the good work yourself!
Cheers!
The promised make command is finally there:
MakerBundle 1.8: Instant User & Login Form Commands
https://symfony.com/blog/ne...
Hi again! :)
I have a question for you. In the last tutorials from Symfony 2 and 3, if I'm not wrong we were using the FOSUserBundle to manage this part and it was really helpful.
I used it too this bundle and now I'm trying to migrate from Symfony 3 to Symfony 4. I realised that in Symfony 3 I had to override the basic templates from the FOSUserBundle and as it says in https://symfony.com/doc/mas..., I could replace theses templates locating the new templates inside app/Resources/FOSUserBundle/views/whatever.html.twig.
My confussion comes when I tried to find the new location from theses templates I created and I want to keep using.
In the new file structure from Symfony 4, there is no more the folder project/app/, so I don't know where to locate theses files.
Could you explain me where I should put these files now in the new structure or how I should manage it now?
Hi Apr
In Symfony 4 you can override bundle templates by putting them into <your-project>/templates/bundles/<bundle-name>/<template>. For more information check this doc page https://symfony.com/doc/cur...
Hope this will help.
Cheers!
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-time-bundle": "^1.8", // 1.8.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"sensio/framework-extra-bundle": "^5.1", // v5.2.0
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.1.4
"symfony/console": "^4.0", // v4.1.4
"symfony/flex": "^1.0", // v1.17.6
"symfony/framework-bundle": "^4.0", // v4.1.4
"symfony/lts": "^4@dev", // dev-master
"symfony/orm-pack": "^1.0", // v1.0.6
"symfony/security-bundle": "^4.0", // v4.1.4
"symfony/serializer-pack": "^1.0", // v1.0.1
"symfony/twig-bundle": "^4.0", // v4.1.4
"symfony/web-server-bundle": "^4.0", // v4.1.4
"symfony/yaml": "^4.0", // v4.1.4
"twig/extensions": "^1.5" // v1.5.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/debug-bundle": "^3.3|^4.0", // v4.1.4
"symfony/dotenv": "^4.0", // v4.1.4
"symfony/maker-bundle": "^1.0", // v1.7.0
"symfony/monolog-bundle": "^3.0", // v3.3.0
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.1.4
"symfony/profiler-pack": "^1.0", // v1.0.3
"symfony/var-dumper": "^3.3|^4.0" // v4.1.4
}
}
Good morning or evening! I wonder if there is any chance to make a redirect to a specific page after a logout?
I tried this
` $this->redirect($this->generateUrl('security_logout', [
as well as $this->redirectToRoute(...) but that doesnt work. I use the configured logout flow through security.yaml
I know it's very edge-casy, but I want to log users out and redirect them if they are logged in while clicking on the "register" route. And while I'm writing this, I'm wondering how to log out procedurally without redirects... for example in a controller.