FOSUserBundle - Symfony2 library that every developer should know

How does it work?

FOSUserBundle stores the user accounts in the database and the user interface in the well-defined file structure. This ensures that interface creating a system of accounts is consistent and convenient.

Installation

Installation of FOSUserBundle is divided into several steps:

Installation of the library

Similar to other bundles, FOSUserBundle is installed by using Composer, the tool attached to the Symfony that allows for automatic installation of chosen bundle and all its dependencies.

$ composer require friendsofsymfony/user-bundle "~2.0@dev"

Right now we have to add the following code to the app/kernel.php file

<?php
// app/AppKernel.php

public function registerBundles()
{
$bundles = array(
// ...
new FOS\UserBundle\FOSUserBundle(),
// ...
);
}

Creating User Class

The next step is to create a user class. In its simplest form it looks like this

<?php
// src/AppBundle/Entity/User.php

namespace AppBundle\Entity;

use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

public function __construct()
{
parent::__construct();
// your own logic
}

}

Configuration of the library

Easy part is over, now it’s time to do something more difficult, which mens the configuration of FOSUserBundle. Because of the security of Symfony, it can’t be simplified or even automated - we have to do it manually.

config.yml

​The first configuration file contains information about the type of database being used and the location of the user class. Type in the following data:

fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\User

The first line indicates the type of service, which in our case is orm, the second one contains the name of the firewall. Let’s follow the default approach and just call it main. The third line shows the created user class.

routing.yml

fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
prefix: /

The code above indicates that FOSUserBundle should be accessible from the main path.

This means, among other things, that the following paths will now be available in the application:

  • /login - where users will log in,
  • /logout - where users will log out,
  • /profile - where user profile will be,
  • /register - registration window.

Alternatively, if we change the prefix to, for example, prefix:/admin, then the paths will also change to /admin/login, etc.

security.yml

security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN

encoders:
FOS\UserBundle\Model\UserInterface: bcrypt

providers:
fos_userbundle:
id: fos_user.user_provider.username

firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true

access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile$, role: IS_AUTHENTICATED_REMEMBERED }
- { path: ^/admin/, role: ROLE_ADMIN }

In this way we've manually overridden the most complicated part of the configuration.

The first section is responsible for building a hierarchy of roles. This means that the person with the admin role will also have access to subpages that require user role, even if it’s not explicitly defined.

Encoders section is responsible for selection of the algorithm used to encrypt the password. It is recommended to use the currently most secure algorithm, which is bcrypt.

Providers section is used internally by FOSUserBundle. Right now there is no need to modify it, therefore we will leave it as it is described above.

Firewalls section is a little more complicated. We start by creating subsection using the same name as in config.yml, which in our example is called main. Then we fill all the subfields, like its shown in the code above.

At the end we need to define the access_control section, which specify what permissions we want to assign to each path.

The most important paths are login, register and profile. All of these sections must be consistent with those from the routing.yml file.

Admin section is an example of how to secure access to the paths that start with /admin/ by requiring the appropriate role (ROLE_ADMIN).

Views

When the configuration is complete we have an almost completed user system. Now we are left with only taking care of the views of our panels. The corresponding files can be found in the vendor/friendsofsymfony/user-bundle/Resources/views/ folder.
To replace one of them, we need to copy it to a app/Resources/views folder and make necessary modifications (while keeping the path to the corresponding sub-folder consistent with original).

Final touches

After the configuration we only have to issue the command:

$ ./app/console doctrine:schema:update --force

And that’s how our new user system is ready to use.

Login window is available at http://localhost:8000/login and the registration is possible at http://localhost:8000/register.

Useful commands

One of the advantages of using FosUserBundle is the ability to manage users using the console. This can be done by writing the following commands:

  • ./app/console fos:user:create - creating new user,
  • ./app/console fos:user:change-password - changing password,
  • ./app/console fos:user:promote - attaching role to user,
  • ./app/console fos:user:demote - deleting user’s roles,
  • ./app/console fos:user:activate - activating the account,
  • ./app/console fos:user:deactivate - deactivating the account.

Alternative tools

As we can read here, FosUserBundle is not a perfect tool and in many cases can be more confusing than usefull.

However, the advantages outweigh the disadvantages in a way that there are no good alternatives. It can be seen as a good thing, because it gives a chance for standardization, but I must admit that at the same time it slows down the development of this bundle. As we know, there is nothing worst for the product’s quality than a monopoly.

In a situation where FosUserBundle is not useful for our project, but we still need user management, we can as an alternative write our own user management system based on Symfony’s libraries. More on this can be read on the official Symfony website:

Pros and cons

ProsConsQuick creation of a simple user systemInability to remove unnecessary fields from the user classCompatibility with almost all bundles from other companiesForced unique login and email address (can’t be easily bypassed)The possibility of extending user classA rapidly growing technical debtReady to use systems for login, registration and email confirmation

Advanced configuration

FosUserBundle has some more advanced capabilities, but it requires additional configuration. Let’s take a look at what we need to use the most popular ones:

Email confirmation and password reset

One of the simplest and most useful functionality is the email confirmation. Additionally, confirmed email also allows to recover the password. This function can be implemented by adding the following configuration, but we must remember to include the correct email and the name of the sender:

# app/config/config.yml
fos_user:
# ...
service:
mailer: fos_user.mailer.twig_swift
from_email:
address: no_reply_@moja.strona.pl
sender_name: Moja Strona
registration:
confirmation:
enabled: true
template: AppBundle:Email:register_confirmation.email.twig
resetting:
email:
template: AppBundle:Email:password_resetting.email.twig

Then we have to create the corresponding files in src/AppBundle/Resources/views/Email/ folder. In both cases we receive access to the confirmation link through the confirmationUrl variable.

The example file looks like this:

{% block subject %} Registration confirmation {% endblock %}
{% block body_html %}
<html>
<head>
</head>

<body>
To confirm your registration visit the site
<a href="{{confirmationUrl}}"> {{confirmationUrl}} </a>
</body>
</html>
{% endblock %}
{% block body_text %}
To confirm your registration visit the site
{{confirmationUrl}}
{% endblock %}

The file contains 3 blocks:

  1. subject - (necessary) Title of the message,
  2. body_html - (optional) content of the message in HTML format (used by most email programs),
  3. -body_text - (necessary) content of the message in the text format (used when HTML is not specified and when email program is not supporting HTML).

Confirmation by admin

Sometimes we want the user's account to be activated by the admin. This is possible with the following configuration:

# app/config/config.yml
fos_user:
# ...
service:
mailer: fos_user.mailer.noop
registration:
confirmation:
enabled: true

Please note that it will block the possibility to recover the password. If, however, you would like to have the possibility to both activate accounts as admin and reset the password as a user, it is necessary to write your own mailer, which is beyond the topic of this article.

Alternatively, the previous method can be used without placing the link in the activation message.

Sign in using email address

If we want to provide the user with the ability to log in with their email address, it is possible thanks to the following configuration:

# app/config/security.yml
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email

This will allow users to use both the user name and email address to log in. Unfortunately, if we want to block the ability to log in using the login it is necessary to write your own UserProvider, which is beyond the topic of this article. You can read more about it HERE.

Useful links

Navigate the changing IT landscape

Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .