Symfony2自定义异常和身份验证令牌

时间:2013-12-23 20:46:48

标签: php security exception symfony token

[注意]也请参阅最终解决方法,向下滚动

经过12个小时的轰炸和阅读大量材料后,我放弃了并要求别人帮我解决“安全上下文不包含身份验证令牌。一个可能的原因可能是没有为防火墙配置防火墙这个网址。)“问题。

如何将安全上下文正确传递给我的自定义处理程序?

我有以下设置:

  • Env:prod
  • 调试:false

security.yml

jms_security_extra:
    secure_all_services: false
    expressions: true

security:
    encoders:
        Symfony\Component\Security\Core\User\User: plaintext
        path\to\SsoAccount: plaintext

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

    providers:
        sso:
            id: sso_account_provider

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

        sso:
            pattern:    ^/
            logout:
                path:   sso_logout
                target: homepage
            anonymous: ~

    access_control: ~

config.yml

# Twig Configuration
twig:
    exception_controller: "acme.controller.exception_controller:showAction"
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    globals:
        project_url: "%cfg_project_url%"
        sso_server:  "%cfg_sso_server%"
        sso_server_admin:  "%cfg_sso_server_admin%"
        google_drive_api_key:   "%cfg_google_drive_api_key%"
        oauth_client_id:        "%cfg_oauth_client_id%"
    form:
        resources:
            - "MainBundle:Form:fields.html.twig"

services:
    acme.controller.exception_controller:
        parent: twig.controller.exception
        class:  Acme\MainBundle\Controller\ExceptionController
        arguments: ["@security.context"]
        calls:
            - [ 'setContainer', ['@service_container']]
            - [ 'setSecurityContext', ['@security.context']]

的Acme / MainBundle /控制器/ ExceptionController.php

<?php
namespace Acme\MainBundle\Controller;

use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\Security\Core\SecurityContext;

class ExceptionController extends BaseExceptionController
{
    protected $securityContext;
    protected $container;

    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function setSecurityContext(SecurityContext $context)
    {
        $this->securityContext = $context;
    }

    public function showAction(
        Request $request,
        FlattenException $exception,
        DebugLoggerInterface $logger = null,
        $format = 'html'
    ) {
        $this->exceptionClass = $exception->getClass();

        return parent::showAction($request, $exception, $logger, $format);
    }

    protected function findTemplate(Request $request, $format, $code, $debug)
    {
        /*********************/
        /** PROBLEM IS HERE **/
        //$user = $this->securityContext->isGranted('ROLE_USER');
        /** PROBLEM IS HERE **/
        /*********************/

        if (!$debug) {
            return 'MainBundle:Main:error404.html.twig';
        }

        return parent::findTemplate($request, $format, $code, $debug);
    }
}

的Acme / MainBundle /资源/视图/主/ error404.html.twig

{% block body %}
    {{ render(controller('MainBundle:Main:error404')) }}
{% endblock %}

的Acme / MainBundle /控制器/ MainController.php

/**
 */
public function error404Action()
{
    /** ALWAYS return null **/
    $getUser = $this->getUser();
    /***********************/

    if (!empty($getUser)) {
        $account = $this->getUser()->getAccountInfo();
        $user    = $account->Account["0"]->user;

        return $this->render(
                    'MainBundle:Main:error404_loggedin.html.twig',
                        array(
                            'account' => $account,
                            'user'    => $user,
                        )
        );
    }

    return $this->render(
                'MainBundle:Main:error404_not_loggedin.html.twig',
                    array()
    );
}

“未登录”错误404没有任何问题,因为没有添加任何安全性,但是为登录成员显示不同的一个让我感到痛苦,所以请提供建议。谢谢!


*最终解决方法*


的Acme / MainBundle /控制器/ MainController.php

/**
 * @Route("/404", name="publicError404")
 */
public function publicError404Action()
{
    $response = new Response();
    $response->setStatusCode(404);

    $templateFile = 'MainBundle:Main:error404_not_loggedin.html.twig';
    $templateData = array();

    $getUser = $this->getUser();
    if (!empty($getUser)) {
        $templateFile = 'MainBundle:Main:error404_loggedin.html.twig';

        $account = $this->getUser()->getAccountInfo();
        $user    = $account->Account["0"]->user;

        $templateData['account'] = $account;
        $templateData['user']    = $user;
    }

    $templateData['token']     = $this->getRequest()->getSession()->getId();
    $templateData['sso']       = $this->container->getParameter('sso_token');
    $templateData['timestamp'] = time(); //date(DATE_RFC822)

    return $this->render($templateFile, $templateData, $response);
}

应用/配置/ config.yml

services:
    acme.controller.exception_controller:
        class:  Acme\MainBundle\EventListener\NotFoundRouteListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
        arguments: [ @router, @service_container, @kernel ]

的Acme / MainBundle /事件监听/ NotFoundRouteListener.php

<?php
namespace Acme\MainBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\Router;

class NotFoundRouteListener
{
    protected $container;
    protected $router;
    protected $kernel;

    public function __construct(Router $router, ContainerInterface $container, Kernel $kernel)
    {
        $this->router    = $router;
        $this->container = $container;
        $this->kernel    = $kernel;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $isProduction = ($this->kernel->getEnvironment() == "prod") ? true : false;
        $isDebug      = ($this->kernel->isDebug() == true) ? : false;
        $routeName    = $this->container->get('request')->get('_route');

        /**
         * Display only if:
         *      - env = prod
         *      - debug = false
         *      - route = empty
         */
        if ($isProduction && !$isDebug && empty($routeName)) {
            $url = $this->router->generate('publicError404');
            $event->setResponse(new RedirectResponse($url));
        }
    }
}

我不会粘贴error404_not_loggedin.html.twig和error404_loggedin.html.twig的内容,因为问题和解决方案不需要它。

1 个答案:

答案 0 :(得分:3)

安全逻辑在路由逻辑之后执行(在2.1之前,之前执行)。这意味着路由器抛出的404错误无法使用安全性,因为还没有关于安全性的信息。

当然,你也可以在安全信息可用的控制器中抛出404错误。要使它在任何情况下都可用,请检查安全上下文是否可用并设置,如果没有,只需渲染未登录的模板