我找不到有关如何使用CSRF令牌生成链接的文档,例如在Symfony 1.4中:
link_to(__('Delete'), url_for('ntw-delete', $network), array('confirm' => 'Are you sure?', 'method' => 'delete'))
更新:我为此创建了一个枝条扩展。也许这对某人有帮助
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>
现在你可以使用:
{{ 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?'}) }}
我是控制器:
//check CSRF token
if (FALSE === $this->get('form.csrf_provider')->isCsrfTokenValid('delete-admin', $request->get('_token')))
{
throw new AccessDeniedHttpException('Invalid CSRF token.');
}
答案 0 :(得分:3)
来自 Symfony 4 的解决方案,来自此处的文档http://symfony.com/doc/current/security/csrf.html:
Twig模板:
<a href="{{ path("remove", { "id" : 1, "csrf_token" : csrf_token('remove') }) }}">
{{ "remove" | trans }}
</a>
控制器:
/**
* @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
}
}
答案 1 :(得分:2)
我有同样的问题。首先,我在Controller中生成令牌并传递给twig文件
$intentions = 'unknown';
$csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken($intentions);
return array('csrfToken'=>$csrfToken);
而不是来自twig文件,你可以访问令牌
var token = '{{csrfToken}}'