【问题标题】:How to make a redirection in a Listener如何在监听器中进行重定向
【发布时间】:2014-12-26 16:09:33
【问题描述】:

我正在尝试在侦听器中进行重定向,但它不起作用。

我的听众:

<?php
// AuthenticationListener.php

namespace Acme\UserBundle\Listener;

use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Routing\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;

class AuthenticationListener
{
    protected $router;

    public function __construct(Router $router)
    {
        $this->router = $router;
    }

    public function onAuthenticationFailure(AuthenticationFailureEvent $event)
    {
        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
            // var_dump('Hello'); die();
            return new RedirectResponse($this->router->generate('mobile_login'));
        }
    }

    public function onAuthenticationSuccess(InteractiveLoginEvent $event)
    {
        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
           return new RedirectResponse($this->router->generate('mobile_home'));
        }
    }
}

我需要这个,因为我有 2 个登录表单:一个用于 PC,一个用于移动设备。因此,如果用户在登录/密码时出错,我需要显示正确的页面 /login/m/login

我的脚本有效。如果我取消注释 var_dump('Hello'); 我会看到“你好”。除了我的重定向之外,一切都很好。我不知道为什么。我没有错误,symfony 只是不关心并将我重定向到 /login。显然这是“正常的”,我并不孤单,但我找不到解决方案。我刚刚在某个需要 Dispacher 的地方读到,但我不知道它是如何工作的。

如果你有一个很棒的解决方案。

编辑

我的 UserBundle/[...]/service.yml

# authentication failure event listener
acme_user.security.authentication_failure_event_listener:
    class: Acme\UserBundle\Listener\AuthenticationListener
    arguments: [@router]
    tags:
        - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }

# authentication success event listener
acme_user.security.interactive_login_listener:
    class: Acme\UserBundle\Listener\AuthenticationListener
    arguments: [@router]
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: onAuthenticationSuccess }

我的 UserBundle/[...]/routing.yml

mobile_login:
    pattern:  /m/login
    defaults: { _controller: AcmeUserBundle:Mobile:login }

编辑阿卜杜拉·阿尔法克

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    role_hierarchy:
        ROLE_MODO:        ROLE_USER
        ROLE_ADMIN:       ROLE_MODO
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_MODO, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        mobile:
            pattern:  ^/m
            anonymous: ~
            form_login:
                check_path: /m/login_check
                login_path: /m/login
                default_target_path: /m/admin
            logout:
                path:   /m/logout
                target: /

        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
            logout:       true
            anonymous:    true
            switch_user:  true
            remember_me:
                key:      "%secret%"
                lifetime: 31536000
                path:     /
                domain:   ~

    always_authenticate_before_granting: true

    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/m/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }

MobileController.php

<?php

namespace Acme\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContext;

class MobileController extends Controller
{

    public function loginAction(Request $request)
    {
        /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
        $session = $request->getSession();

        // get the error if any (works with forward and redirect -- see below)
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
        } elseif (null !== $session && $session->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        } else {
            $error = '';
        }

        if ($error) {
            // TODO: this is a potential security risk (see http://trac.symfony-project.org/ticket/9523)
            $error = $error->getMessage();
        }
        // last username entered by the user
        $lastUsername = (null === $session) ? '' : $session->get(SecurityContext::LAST_USERNAME);

        $csrfToken = $this->container->has('form.csrf_provider')
            ? $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate')
            : null;

        return $this->render('AcmeUserBundle:Mobile:login.html.twig', array(
            'last_username' => $lastUsername,
            'error'         => $error,
            'csrf_token' => $csrfToken,
        ));
    }

【问题讨论】:

  • 显示您如何为侦听器和您的 mobile_login 路由定义服务。
  • @jakon 我编辑了。如果您需要更多信息,请告诉我。

标签: symfony


【解决方案1】:

你不必通过“Listener” 最好的方法是通过安检

security.yml:

firewalls:

    dev:
        pattern:  ^/(_(profiler|wdt)|css|images|js)/
        security: false

    mobile:
        pattern:  ^/m
        anonymous: ~
        form_login:
            check_path: /m/login_check
            login_path: /m/login
            default_target_path: /m/admin
        logout:
            path:   /m/logout
            target: /

    main:
        pattern:  ^
        anonymous: ~
        form_login:
            check_path: /login_check
            login_path: /login
            default_target_path: /admin
        logout:
            path:   /logout
            target: /


access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/m/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }

routing.yml :

mobile_login:
    pattern:  /m/login
    defaults: { _controller: AcmeUserBundle:Mobile:login  }

mobile_check_special:
    pattern:  /m/login_check

mobile_logout_special:
    pattern:  /m/logout

【讨论】:

  • 同样,我转到 m/login,输入错误的登录名,然后我重定向到 /login 并显示错误消息。我用完整的 security.yml 编辑了我的第一篇文章
  • 你能告诉我操作代码吗 => AcmeUserBundle:Mobile:login
  • 不,我是个白痴,忘了把&lt;form action="{{ path("fos_user_security_check") }}" method="post"&gt;改成&lt;form action="{{ path("mobile_check_special") }}" method="post"&gt;
【解决方案2】:

尝试类似的方法,未测试:

security.yml:

...

firewalls:
    some_area:
        ...

        form_login:
            failure_handler: custom.security.authentication_failure_handler
            login_path: /login
            check_path: /login_check

        logout:
            path:   /logout
            target: /

...

AuthenticationFailureHandler.php

class AuthenticationFailureHandler extends DefaultAuthenticationFailureHandler
{

    private $router;

    public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null, RouterInterface $router)
    {
        parent::__construct($httpKernel, $httpUtils, $options, $logger);

        $this->router = $router;
    }

    ....

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {

        if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'])){
            return $this->httpUtils->createRedirectResponse($request, $this->router->generate('mobile_login'));
        }

        return parent::onAuthenticationFailure($request, $exception);
    }
}

服务配置:

....

<service id="custom.security.authentication_failure_handler" class="%custom.security.authentication_failure_handler.class%" public="false">
    <argument type="service" id="kernel" />
    <argument type="service" id="security.http_utils" />
    <argument type="collection" />
    <argument type="service" id="logger"  on-invalid="ignore" />
    <argument type="service" id="router" />
</service>
....

【讨论】:

    【解决方案3】:

    试着像这样写你的服务声明:

    services:
    myservice:
        class: My\MyBundle\MyService
        arguments: [ @router ]
        scope: request
    

    我认为你错过了范围属性。

    【讨论】:

    • 收到错误:InactiveScopeException:您无法创建非活动范围(“请求”)的服务(“acme.security.authentication_failure_event_listener”)。
    • 你能不能在服务声明的最后加上lazy: true,然后再试一次!
    • 删除范围和惰性选项并像这样更改您的响应: public function onAuthenticationFailure(AuthenticationFailureEvent $event) { if(preg_match("/m\/login/", $_SERVER['HTTP_REFERER'] )){ $url = $this->router->generate('mobile_login'); $response = new RedirectResponse($url); $event->setResponse($response); }
    • 看看这篇文章我认为你还必须添加 onKernelController 函数:stackoverflow.com/questions/12916439/…
    猜你喜欢
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 2021-10-05
    • 1970-01-01
    相关资源
    最近更新 更多