Authorization and access restriction in Symfony framework (Lesson 14)

So, in this note we will learn how to restrict access to sections of a website written using Symfony framework. Symfony framework provides powerful tools for access control, which allow you to restrict access both by url and entire controllers.

If you are confused about the concepts of authentication, identification, and authorization, I recommend reading this first.

First, a little theory.

What we need is done through a configuration file (yaml by default, app/config/security.yml).

When a user makes a request to a url protected by a firewall, the security system is activated.

 

Authentication/Authorization process in Symfony framework
Authentication/Authorization process in Symfony framework

 

The system first determines if authentication is needed, if yes - then it returns a response to the user initiating the authentication process. After entering the data, the presence of the user, their rights, and if sufficient, the originally requested page is returned.

User information can be stored either in the configuration file (app/config/security.yml) (if you have 1-2 users, including the admin - it will suffice =)) or in the database (if you have a complex multi-user system).

Let's consider a basic example:


# app/config/security.yml
security:
    firewalls:
        secured_area:
            pattern: ^/
            anonymous: ~
        form_login:
            login_path: login
            check_path: login_check
    access_control: - { path: ^/admin, roles: ROLE_ADMIN }
    providers: in_memory: memory: users: ryan: { password: ryanpass, roles: 'ROLE_USER' } admin: { password: kitten, roles: 'ROLE_ADMIN' }
    encoders: SymfonyComponentSecurityCoreUserUser: plaintext

 

In the firewalls section, we specified that the security system is activated for all incoming requests (pattern sets the url template), and in the next line we allowed access for unauthenticated users.

The form_login login_path and check_path parameters specify the routes for the login form and data validation (Form - a regular action of a controller, in the simplest case, it will not need to describe the login_check action).

In the next section, access_control, we again set the url template, but this time for the protected part of the resource, and specify which types ("roles" in terms of Symfony framework) of users have access to the protected part.

The next section allows you to specify the sources of user credentials. In this example, they are directly in the configuration file. Note that if the password starts with a number, it should be enclosed in quotes. Also note that by gaining access to the configuration file, third parties can easily find out your password.

To display the login form, you need to create a routing for it. For example, like this:

# app/config/routing.yml
login:
  pattern: /login
  defaults: { _controller: AcmeSecurityBundle:Security:login }
login_check:
  pattern: /login_check

And the controller action itself (taken from the official Symfony framework guide):

// src/Acme/SecurityBundle/Controller/SecurityController.php;
namespace AcmeSecurityBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SymfonyComponentSecurityCoreSecurityContext;
class SecurityController extends Controller
{
  public function loginAction()
  {
  $request = $this->getRequest();
  $session = $request->getSession();
  // get the login error if there is one
  if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
   $error = $request->attributes->get(
   SecurityContext::AUTHENTICATION_ERROR
  );
  } else {
   $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
   $session->remove(SecurityContext::AUTHENTICATION_ERROR);
  }
 return $this->render(
 'AcmeSecurityBundle:Security:login.html.twig',
 array(
 // last username entered by the user
 'last_username' => $session->get(SecurityContext::LAST_USERNAME),
 'error' => $error)
 );
 }
}

And the template itself:


{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #}
{% if error %}
    <div>{{ error.message }}</div>
{% endif %}

<form action="{{ path('login_check') }}" 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" />
    
    <button type="submit">login</button>
</form>

So, we have learned how to restrict access to sections of a project written using the Symfony framework using configuration files. The list of users is stored in the same files. In the next notes, we will learn how to use a database for this purpose.