📜 ⬆️ ⬇️

Symfony2: logging out

image One of the golden rules of Symfony2 is to never hardcode any links and paths inside the code or templates. Observing this rule and generating links through a router will greatly facilitate your life. However, there is one thing that I often observe: people continue to hardcod exiting links, for example, “/ logout”, only the logout process itself is a bit more complicated than it may seem and using such a link can work in most cases, but this will not be the best solution.

Some information about the component (and the bundle) Symfony2 Security


Most developers know that you can make several protected sections within one project. For example, it may be a panel for regular users (registered users) with the / secure path. And, perhaps, in your project there may be a separate administration panel at / admin address and there is a separate zone for users of the API, which is located in the section with the address / api . Also, you can make a “protected zone”, which does not need any protection at all - this approach is used in the Symfony2 toolbar for developers. In the end, you can generally transfer all this into one big zone, in which several options will be implemented to determine who has access to the protected part of the project. In general, although the division of the project into separate zones makes your project more difficult, it provides some advantages.

Each of the protected zones calls up its own firewall, which determines whether to authenticate the user or not. Each firewall is separate from the others: if you authenticate with one of them, it does not mean that you are automatically authenticated with others and there is only one active firewall (the one that matched the URL pattern). This is important because different firewalls can use different databases or simply use different authentication methods (for example, the API can use OAuth Token, while the remaining sections can use the login form).

It also means that each firewall has different logout paths, and for some of them logout as such does not exist. Security.yml example
')
#   dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false #   superadminstuff: pattern: ^/admin http_basic: provider: memory_user_provider realm: "Super Admin section!" #        main: pattern: ^/ form_login: provider: fos_userbundle csrf_provider: form.csrf_provider login_path: /login logout: true 

This is the “firewall” block in security.yml and it defines 3 firewalls - dev , superadminstuff and main . dev does not use authentication at all (security = false), which means that access is allowed to everyone and the paths "/ js", "/ css" and others are not controlled by the main firewall.

The following set of rules protect the administration area. It uses http_basic as an input, that is, the browser will display a dialog box in which it will ask you to specify a username and password (in fact, this is not very safe, since they will be transmitted as plain text). Moreover, the browser will send a login and password with each request to the project. Symfony2 can verify this data using the “memory_user_provider” provider, the block of which I did not cite, but it usually indicates several standard users and their username / password (directly in the configuration file, not in the database).

In http-basic there is actually no logout because the only way out is to stop sending requests. Clearing the cache or restarting the browser usually helps to make a logout in this case.

The last firewall is main. Instead of http-basic, he uses the login form. It uses FOSUserBundle, which has its own login form and methods for processing it, so the only thing that is required from the developer is to customize them a little, and not write your own.

In case you open the page in this firewall and have not logged in before - Symfony2 will automatically redirect the user to the login page, which is specified in the login_path parameter in the form_login block. Usually (by default), this is the path with the / login address (you can change it as you like or even, if you like, you can specify the route). Once a user has logged in, Symfony2 will save the user and role within his session and the next time the user is prompted, he will not have to log in again.

The exit from such a firewall is quite simple - you need to go to its exit page. But what is this page?

In the example above, the “logout: true” parameter is used. It should be noted that this parameter is located in the firewall block, and not in the form_login block. By specifying logout: true , we tell Symfony2 to use the standard logout settings, namely:

 logout: csrf_parameter: _csrf_token csrf_token_generator: ~ csrf_token_id: logout path: /logout target: / success_handler: ~ invalidate_session: true delete_cookies: name: path: null domain: null handlers: [] 

As you can see, the path is indicated by which the exit will take place. But there is one oddity: by default, the logout listener is launched before calling any controller or action, and then redirects to the page specified in the “target” parameter. If you have your own logout event handler, which is specified in the “handlers” parameter, and it does NOT return an HTTP Response object, then the current route is called. That is, by default, your controller / action will not be called, BUT they must be specified (that is, the Symfony2 router must be made aware of it). For this reason, you can find a strange action logout in the FOSUserBundle that throws an exception, since it will never be called.

Logout


So what to do with the exit? First of all, do not hardcore the URL. Even if you use the route instead of the url, you can change it inside the configuration and the output will stop working. What really should be done is to specify via twig the link or route specified in the configuration. Fortunately, SecurityBundle has an extension for twig that will help to do this. These are the logout_url and logout_path functions. These functions receive the firewall id as an input (for example, “main”, “dev”, etc.) and generate the correct output address for it:

 <a href="{{ logout_path('main') }}">Logout</a> 

In this case, the correct address will be sampled and csrf-token will be added as a bonus, if it was specified in the configuration. Thus, instead of specifying the page address in the template, you need to specify the firewall that is currently being used.

True, now your templates know more than necessary and you must specify the name of the firewall manually. In most cases, this is normal, but sometimes it can cause problems (for example, if you use the menu where twig is used). To avoid problems with this, it is possible to get the name of the current firewall, albeit a bit wrong:

 <a href="{{ logout_path(app.security.token.providerKey) }}">Logout</a> 

Inside the security context token is the name of the current firewall that we need. The “wrong” solution is that the global variable app.security in Symfony version 2.6 will be deprecated and removed in version 3.0. In time, I am sure there will be other ways of generating a way out.

Source: https://habr.com/ru/post/240841/


All Articles