Remember me no longer works in Symfony 5 after transferring to keeping session in DB

Viewed 288

I created sessions within the DB, and that seems to be working well. The DB sessions followed this: https://symfony.com/doc/current/session/database.html

Now the remember me function ceases to function, so now I viewed this: https://symfony.com/doc/current/security/remember_me.html#remember-me-token-in-database

I attempted to implement this, but it doesn't seem to be working. The Database is empty when ever I log in and use the remember me function.

This is how my services.yaml file looks like:

# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    app.profile_picture: '%kernel.project_dir%/%env(uploadPath)%/profiles/'
    app.projects: '%kernel.project_dir%/%env(uploadPath)%/projects/'
    app.stripe_secret_key: '%env(stripe_secret_key)%'
    app.stripe_connect_id: '%env(stripe_connect_id)%'
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        bind:
            $profilePicture: '%app.profile_picture%'
            $stripeSecretKey: '%app.stripe_secret_key%'
            $stripeConnectId: '%app.stripe_connect_id%'
            $projects: '%app.projects%'

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'
            - '../src/Tests/'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller/'
        tags: ['controller.service_arguments']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones
    Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
        arguments:
            - '%env(DATABASE_URL)%'
    Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider: ~
    app.custom.limiter:
        class: App\Limiter\CustomLimiter
        arguments:
            - '@limiter.max_login_failure'

Security.yaml:

remember_me:
        secret:   '%kernel.secret%'
        lifetime: 604800 # 1 week in seconds
        path:     /
        token_provider: 'Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider'

Doctrine.yaml:

doctrine:
    dbal:
        override_url: true
        url: '%env(resolve:DATABASE_URL)%'
        schema_filter: ~^(?!rememberme_token)~

        # IMPORTANT: You MUST configure your server version,
        # either here or in the DATABASE_URL env var (see .env file)
        #server_version: '13'
    orm:
        auto_generate_proxy_classes: true
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        mappings:
            App:
                is_bundle: false
                type: annotation
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App

Is there something I'm missing? Do I have to associate the database session with the remember tokens in the DB too? Not sure what I'm missing, but remember me still isn't working after all of this.

1 Answers

The most common pitfall when implementing "remember me" in Symfony is to render the _remember_me field in a Symfony form without setting its block prefix to an empty string.

For example:

<?php

namespace App\Form\Type\Security;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;

class ConnectType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ...

        $builder
            ->add('_remember_me', Type\CheckboxType::class, [
                'label'    => 'Trust this device',
                'required' => false,
            ]);
    }
}

The generated _remember_me field name will be connect__remember_me in HTML because the block prefix of the ConnectType is connect (look at the getBlockPrefix method of the Symfony\Component\Form\AbstractType class).

As Symfony looks for a posted _remember_me property, you need to set your block prefix to an empty string:

public function getBlockPrefix()
{
    return '';
}
Related