简体   繁体   English

Symfony2与CSRF令牌链接

[英]Symfony2 links with CSRF token

I can't found a documentation about how to generate a link with the CSRF token, like in Symfony 1.4: 我找不到有关如何使用CSRF令牌生成链接的文档,例如Symfony 1.4:

link_to(__('Delete'), url_for('ntw-delete', $network), array('confirm' => 'Are you sure?', 'method' => 'delete'))

UPDATED: I created a twig extension for that. 更新:我为此创建了一个树枝扩展。 Maybe it will help to someone 也许对某人有帮助

src/UmbrellaWeb/Bundle/ExtraTwigBundle/Twig/LinkExtension.php

<?php
namespace UmbrellaWeb\Bundle\ExtraTwigBundle\Twig;

use Twig_Extension;
use Twig_Function_Method;
use Twig_Environment;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;

class LinkExtension extends Twig_Extension
{
    protected $csrfProvider;

    public function __construct(CsrfProviderInterface $csrfProvider)
    {
        $this->csrfProvider = $csrfProvider;
    }

    public function getFunctions()
    {
        return array(
            'link_to' => new Twig_Function_Method($this, 'linkToFunction', array(
                'is_safe' => array('html')
            ))
        );
    }

    /**
     * Build a link with anchor
     * 
     * @param string $path
     * @param string $title
     * @param array $options Available options: 
     *  string 'confirm' - Text for the popup
     *  string 'method' - HTTP Method: post, delete, put
     *  string 'csrfIntention' - CSRF intention. If empty then no CSRF. Not used for GET requests
     *  string 'csrfField' - CSRF field name. _token by default
     *  bool 'escape' - escape title, TRUE by default
     */
    public function linkToFunction($path,$title,array $options = array())
    {
        $default = array(
            'csrf_intention' => '',
            'csrf_field' => '_token',
            'escape' => TRUE
        );

        $options = array_merge($default,$options);

        $ecape = $options['escape'];
        unset($options['escape']);

        $return = '<a href="%s"%s>%s</a>';

        $return = sprintf($return,
            htmlspecialchars($path),
            $this->_tagOptions($this->_options2javascript($options)),
            ($ecape)?htmlspecialchars($title):$title
        );

        return $return;
    }

    function _options2javascript($options)
    {
        // confirm
        $confirm = isset($options['confirm']) ? $options['confirm'] : '';

        unset($options['confirm']);

        // method
        $method = isset($options['method']) ? $options['method'] : false;

        unset($options['method']);

        // CSRF Intention
        $csrfIntention = isset($options['csrf_intention']) ? $options['csrf_intention'] : false;

        unset($options['csrf_intention']);

        // CSRF field name
        $csrfField = isset($options['csrf_field']) ? $options['csrf_field'] : false;

        unset($options['csrf_field']);

        $onclick = isset($options['onclick']) ? $options['onclick'] : '';

        if ($confirm && $method)
        {
            $options['onclick'] = $onclick . 'if (' . $this->_confirmJsFunction($confirm) . ') { ' . $this->_methodJsFunction($method,$csrfIntention,$csrfField) . ' };return false;';
        } else 
            if ($confirm)
            {
                if ($onclick)
                {
                    $options['onclick'] = 'if (' . $this->_confirmJsFunction($confirm) . ') { return ' . $onclick . '} else return false;';
                } else
                {
                    $options['onclick'] = 'return ' . $this->_confirmJsFunction($confirm) . ';';
                }
            } else 
                if ($method)
                {
                    $options['onclick'] = $onclick . $this->_methodJsFunction($method,$csrfIntention,$csrfField) . 'return false;';
                }

        return $options;
    }

    function _confirmJsFunction($confirm)
    {
      return "confirm('".$this->_escapeJs($confirm)."')";
    }

    /**
     * Escape carrier returns and single and double quotes for Javascript segments.
     */
    function _escapeJs($javascript = '')
    {
        $javascript = preg_replace('/\r\n|\n|\r/', "\\n", $javascript);
        $javascript = preg_replace('/(["\'])/', '\\\\\1', $javascript);
        return $javascript;
    }

    function _methodJsFunction($method,$csrfIntention,$csrfField)
    {
        $function = "var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'post'; f.action = this.href;";

        //put, delete HTTP methods
        if ('post' != strtolower($method))
        {
            $function .= "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); ";
            $function .= sprintf("m.setAttribute('name', '_method'); m.setAttribute('value', '%s'); f.appendChild(m);", strtolower($method));
        }

        // CSRF protection
        if ($csrfIntention)
        {
            /**
             * @todo isCsrfEnabled() - check a global config
             */
            if (TRUE)
            {
                $function .= "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); ";
                $function .= sprintf("m.setAttribute('name', '%s'); m.setAttribute('value', '%s'); f.appendChild(m);", $csrfField, $this->csrfProvider->generateCsrfToken($csrfIntention));
            }
        }

        $function .= "f.submit();";
        return $function;
    }

    function _tagOptions(array $options = array())
    {
        $html = '';
        foreach ($options as $key => $value)
        {
            $html .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
        }
        return $html;
    }

    public function getName()
    {
        return 'umbrellaweb_link';
    }
}

services.xml

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="umbrellaweb.twig.link_extension" class="UmbrellaWeb\Bundle\ExtraTwigBundle\Twig\LinkExtension">
            <tag name="twig.extension" />
            <argument type="service" id="form.csrf_provider" />
        </service>
    </services>
</container>

Now in twig you can use: 现在,您可以在树枝中使用:

{{ link_to(path('jk_aa_admin_delete',{'id' : admin.id}),'<img src="del_icon.png"/>',
{'escape':false,'method':'delete','csrf_intention':'delete-admin',
'confirm':'Are you sure?'}) }}

I controller: 我控制器:

//check CSRF token
if (FALSE === $this->get('form.csrf_provider')->isCsrfTokenValid('delete-admin', $request->get('_token')))
{
throw new AccessDeniedHttpException('Invalid CSRF token.');
}

Solution from Symfony 4 , from documentation here http://symfony.com/doc/current/security/csrf.html : 来自Symfony 4的解决方案,位于http://symfony.com/doc/current/security/csrf.html上的文档中:

Twig template: 树枝模板:

<a href="{{ path("remove", { "id" : 1, "csrf_token" : csrf_token('remove') }) }}">
{{ "remove" | trans }}
</a>

Controller: 控制器:

/**
 * @Route("/remove/{id}", name="dashboard_alert_remove")
 *
 * @ParamConverter("alert", class="App:Alert")
 *
 * @param Alert $alert
 */
public function doRemoveAction(Alert $alert, Request $request)
{
    $submittedToken = $request->get('csrf_token');

    if ($this->isCsrfTokenValid('remove', $submittedToken))
    {
        // Do the deletion stuff
    }
}

I had same problem. 我有同样的问题。 First I generated token in the Controller and passed to a twig file 首先,我在Controller中生成了令牌,并传递给了一个树枝文件

 $intentions = 'unknown';  
 $csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken($intentions);

 return array('csrfToken'=>$csrfToken);

than from the twig file you can access the token as 比从树枝文件中,您可以访问令牌

var token = '{{csrfToken}}'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM