2012-08-15 45 views
1

我無法找到有關如何在Symfony的1.4生成具有CSRF令牌的鏈接,比如文檔:Symfony2的鏈接令牌

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.'); 
} 

回答

2

我有同樣的問題。首先,我產生在控制器的令牌,並傳遞給樹枝文件

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

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

不是從樹枝文件,您可以訪問令牌從Symfony的4

var token = '{{csrfToken}}' 
+0

謝謝,我accpet你的答案。但我的問題是如何生成一個鏈接,而不傳遞額外的參數來查看?我已經爲 – Mikhail 2012-10-23 10:35:39

+0

創建了一個樹枝擴展,然後您可以創建一個表單,該表單在隱藏字段中具有標記,並在傳遞標記時鏈接到您的deleteAction,或者可以創建一個ajax請求(如果您不希望用戶成爲重定向),其中包含令牌 – Gigala 2013-04-25 10:22:51

1

解決方案,從這裏的文檔http://symfony.com/doc/current/security/csrf.html

嫩枝模板:

<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 
    } 
}