-->

Silex 2 : Security firewall error with locale (Sil

2019-02-25 12:36发布

问题:

I saw this solution but I can't make it works...

So here is my code, what I tried and what I get :

My code

1/ My Security Provider :

$app->register(new Silex\Provider\SessionServiceProvider());
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'secured' => array(
            'pattern' => '^/',
            'anonymous' => true,
            'logout' => true,
            'form' => array(
                'login_path' => '/login',
                'check_path' => '/login_check'),
            'users' => function () use ($app) {
                return new Myapp\DAO\UserDAO($app['db']);
            },
        ),
    ),
));

2/ My Translator Provider

I use : https://github.com/pmaxs/silex-locale

$app->register(new Silex\Provider\TranslationServiceProvider());
$app->register(new \Pmaxs\Silex\Locale\Provider\LocaleServiceProvider(), [
    'locale.locales' => ['en', 'fr'],
    'locale.default_locale' => 'en',
    'locale.resolve_by_host' => false,
    'locale.exclude_routes' => ['^_']
]);
$app->register(new Silex\Provider\LocaleServiceProvider());

$app->extend('translator', function($translator, $app) {
    $translator->addLoader('yaml', new YamlFileLoader());
    // The translation file : one by langage, add new here
    $translator->addResource('yaml', __DIR__.'/../src/locales/en.yml', 'en');
    $translator->addResource('yaml', __DIR__.'/../src/locales/fr.yml', 'fr');

    return $translator;
});

This way my route have no /{_locale}/ but still works when I have /my-path, /locale/my-path.

3/ My Login Controller

$app->get('/login', function(Request $request) use ($app) {
    return $app['twig']->render('login.html.twig', array(
        'error'         => $app['security.last_error']($request),
        'last_username' => $app['session']->get('_security.last_username'),
    ));
})->bind('login');

What I tried - The error I get

  • When my URL is /login it works : I came back to my Home page connected.
  • When my URL is /fr/login it doesn't work : my URL became /fr/login_check and send me a error 404 (this is normal because I have no view / page for this URL but no idea why it tries to display this page and don't connect me as before).

So I tried to change this in my Security Provider:

 'form' => array(
     'login_path' => '/login',
     'check_path' => '/{_locale}/login_check'),

It give me a error 500 : An exception has been thrown during the rendering of a template ("Unable to generate a URL for the named route "login_check" as such route does not exist.").

So I came back to my other Security Provider (without the /{_locale}/) and change my login controller as suggested in the solution I saw :

$app->get('/{_locale}/login', function(Request $request) use ($app) {
    return $app['twig']->render('login.html.twig', array(
        'error'         => $app['security.last_error']($request),
        'last_username' => $app['session']->get('_security.last_username'),
    ));
})->bind('login');
  • Now when I try to log with my default locale (en), I have this URL /en/login and it works.
  • When I try to change langage for French I have this URL /fr/en/login to login and I came back to my error 404 on URL /fr/login_check.

I have the same problem when I try to LOGOUT from /fr/my-page with a error 404 on URL /fr/logout...

Any idea to make the Silex Security Provider works with pmaxs/silex-locale ?

One collegue suggested me to stay in "en" for the login and logout (because it works), even if my user chose an other langage.

Do you think it's a good idea? (I'm not 100% okay because this way I can't translate my content)

EDIT :

Since I have no anwser to my question, I tried to check my two routes /login_check and /logout to see if I can change them, do you know where I can find them?

Then, I tried to make some redirection before going to those two routes, but don't know how I can do it...the idea :

// If I log from those URL, it works
/login
/en/login

// If I log from those, it doesn't works :
/fr/login
/fr/fr/login

// So from the URL that doesn't works, I'd like to do :
/fr/login ---> redirect to /login ---> execute code
/fr/fr/login ---> redirect to /en/login ---> execute code

And the same with /logout. Any idea if I can do it and how?

END EDIT

PS : Here is an other question about this project where I explain how I allow user to change langage on the website : Silex : allow user to change langage by clicking on html element and keeping clean URL

回答1:

I think I manage to solve my problem this way :

1/ To dodge my error 404 where I login and logout when I have another locale than en, I redirect the user in en before my check_path and logout :

// The login form action
<form role="form" action="{{ locale_generate('en', 'login_check') }}" method="post">

// The logout
<a href="{{ locale_generate('en', 'logout') }}"> <span class="log">{{ 'logout'|trans }}</span></a>

This way it works but user came back in english all the time, so I have to redirect him in my page but with the same locale than before.

2/ So I add the selected langage in session (if I have no $_SESSION['langue'], I use my default locale as value : en)

//===============================================
// My Ajax call where I send the selected langage value
//===============================================
$(".change_langue").on("click", function() {
    var new_langue = $(this).data("lg");

    $.ajax({
        url: "{{ path('new-langue') }}",
        type: 'POST',
        data: {'langue': new_langue},
        success: function (resp) {
            console.log(resp);
        },
        error: function (resp) {
            console.log(resp);
        }
    });
});

//========================================================
// My controller where I set the value in session
//========================================================
$app->post('/new-langue', function(Request $request) use ($app) {
    $new_langue = $request->get('langue');

    $app['session']->set('langue', $new_langue);
    $result['new_langue'] =  $app['session']->get('langue');

    return new Response(json_encode($result));

})->bind('new-langue');

3/ Then I change my default login path when I registered my SecurityProvider :

$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'secured' => array(
            'pattern' => '^/',
            'anonymous' => true,
            'form' => array(
                'login_path' => 'login',
                'check_path' => '/login_check',
                'always_use_default_target_path' => true,  // I add this line
                'default_target_path' => '/login/redirect' // I add this line
            ),
            'logout' => array(
                'logout_path' => '/logout',
                'invalidate_session' => true,                      
            ),
            'users' => function () use ($app) {
                return new _mypixers_silex\DAO\UserDAO($app['db']);
            },
        ),
    ),
));

4/ And now in my new /login/redirect controller I check the $_SESSION['langue'] value and redirect to the right langage :

//========================================================
// LOGIN REDIRECT
//========================================================
$app->get('/login/redirect', function(Request $request) use ($app) {
    $session_langue = $app['session']->get('langue');
    if (empty($session_langue)) {
        $session_langue = 'en';
    }
    return $app->redirect($app['locale.url_generator']->generate($session_langue, 'pixers'));

})->bind('login_redirect');

This way I have no more error when I login or logout with an other locale than en and the user stay in his current langage.

PS : I still come back to english when I logout right now, but I'm working on a solution. I will edit my anwser when it's done