symfony 注销后避免浏览器后退按钮

avoid browser back button after symfony logout

我在 symfony 项目中工作。它几乎准备就绪,身份验证流程正常...但是在用户注销后,他可以通过按浏览器中的后退按钮返回系统。

用户无法使用该系统,如果他点击某些 link o 刷新页面,就会出现登录页面。但是他可以看到申请最后一页的信息。

这是一种使用 symfony 来防止这种行为的方法吗? BR...

security.yaml

security:
    encoders:
        App\Entity\Usuario:
            algorithm: bcrypt
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\Usuario
                property: usuario
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: lazy
            provider: app_user_provider
            form_login:
                login_path: sac_login
                check_path: sac_login
                csrf_token_generator: security.csrf.token_manager
                default_target_path: sac_login
                always_use_default_target_path: true
            logout:
                path: sac_logout
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/sala, roles: ROLE_SALA }
        - { path: ^/estacionario, roles: ROLE_ESTACIONARIO }
        - { path: ^/registro, roles: ROLE_REGISTRO }
        - { path: ^/direccion, roles: ROLE_DIRECTIVO }
        - { path: ^/transcripcion, roles: ROLE_TRANSCRIPCION }
        - { path: ^/reprografia, roles: ROLE_REPROGRAFIA }

PD1:老板回答后,用户可以注销并点击浏览器后退按钮,登录页面保持不变,但如果另一个角色不同的用户登录时会出现403错误,因为应用程序重定向到url 我们应该避免的。

PD2:应用程序没有不安全的区域,所有用户都需要登录才能访问他们的工作区域。我通过在用户 table 中保存该区域的路由并在 symfony 身份验证系统使用以下代码到达 onAuthenticationSuccess 时加载它来实现这一点:

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        $user = $this->entityManager->getRepository(Usuario::class)->findOneBy(['usuario' => $request->request->get('_username')]);
        $ruta = $user->getRuta();

        return new RedirectResponse($this->urlGenerator->generate($ruta));
    }

这是浏览器的正常行为,但如果您确实需要控制它,则可以使用事件侦听器并设置响应来实现此目的 headers 这样浏览器就不会缓存这些页面.

此侦听器只会根据控制器设置 headers,因此您可以仅为管理页面设置它,例如 App\Controller\AdminController...

将文件放入 src/EventListener/ResponseHeaderListener.php

// src/EventListener/ResponseHeaderListener.php
namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use App\Controller\AdminController;

class ResponseHeaderListener implements EventSubscriberInterface
{
    private $controller;

    public static function getSubscribedEvents()
    {
        return array(
            'kernel.controller' => 'onKernelController',
            'kernel.response' => 'onKernelResponse'
        );
    }

    public function onKernelController(ControllerEvent $event)
    {
        $this->controller = $event->getController();
    }

    public function onKernelResponse(ResponseEvent $event)
    {
        if (!$event->isMasterRequest() || !is_array($this->controller)) {
            return;
        }

        if ($this->controller[0] instanceof AdminController) {
            $response = $event->getResponse();
            
            // Set response headers
            $response->headers->add(array(
                'Cache-Control' => 'nocache, no-store, max-age=0, must-revalidate',
                'Pragma' => 'no-cache'
            ));
        }
    }
}

根据您的需要调整和修改。

为了完成我想要的,首先我需要根据 Bossman 的回答创建 de ResponseHeaderListener class 但是有一个小改动,因为我的系统没有不安全的区域,所有的控制器都需要通过监听器:

<?php

namespace App\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

class ResponseHeaderListener implements EventSubscriberInterface
{
    private $controller;

    public static function getSubscribedEvents()
    {
        return array(
            'kernel.controller' => 'onKernelController',
            'kernel.response' => 'onKernelResponse'
        );
    }

    public function onKernelController(ControllerEvent $event)
    {
        $this->controller = $event->getController();
    }

    public function onKernelResponse(ResponseEvent $event)
    {
        if (!$event->isMasterRequest() || !is_array($this->controller)) {
            return;
        }

        $response = $event->getResponse();
        $response->headers->add(array(
            'Cache-Control' => 'nocache, no-store, max-age=0, must-revalidate',
            'Pragma' => 'no-cache'
        ));

    }
}

其次,更新 security.yaml 主防火墙下的文件:

form_login:
    login_path: sac_login
    check_path: sac_login
    always_use_default_target_path: true

其中 sac_login 是到登录页面的 symfony 路由。

第三步也是最后一步,注释或删除以下代码:

    if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
        return new RedirectResponse($targetPath);
    }

onAuthenticationSuccess 函数中属于 loginFormAuthenticator class.

希望这个回答可以帮助到有类似疑问的人。真的,我不仅在 symfony 中读到过这个问题,而且几天来我一直在努力寻找解决方案。感谢@Bossman 的耐心等待,当然还有他的帮助!!!