Symfony 1.4:自定义表单CSRF错误消息

7

有人能告诉我在Symfony 1.4中如何自定义表单CSRF令牌错误消息吗?我正在使用sfDoctrineGuard进行登录,在这个表单中,每当会话过期且页面仍然打开时,它会抛出一个非常不友好的错误:“检测到CSRF攻击”。类似“此会话已过期。请返回主页并重试”听起来更好。

在表单类中正确的方法是什么?

谢谢。

6个回答

5
唯一的方法似乎是覆盖 sfForm::addCSRFProtection() 方法。

/lib/form/BaseForm.class.php 中,您可以添加以下代码:

class BaseForm extends sfFormSymfony
{
    public function addCSRFProtection($secret = null)
    {
        parent::addCSRFProtection($secret);
        if (array_key_exists(self::$CSRFFieldName, $this->getValidatorSchema())) {
            $this->getValidator(self::$CSRFFieldName)->setMessage('csrf_attack', 'This session has expired. Please return to the home page and try again.');
        }
    }
}

在调用父方法之后,您可以检索与CSRF字段关联的验证器,并更改代码csrf_attack的消息。请注意,您还需要检查验证器是否存在。有些表单可能已经禁用了它们的CSRF保护!希望这可以帮到您!

@naag:非常感谢。我尝试了几个方法,但没有这个,我会试一下的。看起来Symfony的开发人员犯了一个小错误。 - Tom
我编辑了我的答案,加入了一个检查CSRF验证器是否存在的步骤 :-) - naag

3

这些答案都没有说明如何以非hackish的方式(例如更改令牌名称是不好的想法!)删除在错误消息前缀中添加“CSRF token:”标签的方法。

唯一可靠的方法是扩展CSRF验证器以抛出全局错误。 在此过程中,我们还可以更改错误消息。

class myValidatorCSRFToken extends sfValidatorCSRFToken
{
  protected function configure($options = array(), $messages = array())
  {
    parent::configure($options, $messages);
    $this->addMessage('csrf_attack', 'Your session has expired. Please return to the home page and try again.');
  }

  protected function doClean($value)
  {
    try {
      return parent::doClean($value);
    } catch (sfValidatorError $e) {
      throw new sfValidatorErrorSchema($this, array($e));
    }
  }
}

现在,让我们通过在BaseForm中重写sfForm::addCSRFProtection来使用此验证器来设置我们的表单:
public function addCSRFProtection($secret = null)
{
  parent::addCSRFProtection($secret);
  if (isset($this->validatorSchema[self::$CSRFFieldName])) //addCSRFProtection doesn't always add a validator
  {
    $this->validatorSchema[self::$CSRFFieldName] = new myValidatorCSRFToken(array(
        'token' => $this->validatorSchema[self::$CSRFFieldName]->getOption('token')
    ));
  }
}

2
在1.4.4版中,我需要像这样修改naag的代码...
public function addCSRFProtection($secret = null)
{
  parent::addCSRFProtection($secret);
  if (isset($this->validatorSchema[self::$CSRFFieldName])) {
    $this->validatorSchema[self::$CSRFFieldName]->setMessage('csrf_attack', 'This session has expired. Please refresh and try again.');
  }
}

这样做可以使其正常工作,但“csrf token:”仍然出现在错误消息中。

2

在之前的答案基础上,这是我使用的代码:

public function addCSRFProtection($secret = null)
  {
    parent::addCSRFProtection($secret);
    if (isset($this->validatorSchema[self::$CSRFFieldName])) {
      $this->validatorSchema[self::$CSRFFieldName]->setMessage('csrf_attack', 'This session has expired. Please refresh and try again.');
      $this->getWidgetSchema()->getFormFormatter()->setNamedErrorRowFormatInARow("    <li>%error%</li>\n");
    }
  }

NamedErrorRowFormatInARow的默认值为"<li>%name%: %error%</li>\n",添加了名称和冒号。请注意,这将更改所有表单和全局错误的值。
您还可以通过创建自定义表单格式化程序并在所需的表单中使用它来更改该字段。您可以查看这里的文档以获取更多信息。

1

我认为“csrf token:”前缀可以通过全局设置CSRF令牌字段的标签来删除或自定义。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接