我想在我的控制器中为我的添加,更新和删除操作创建一个过滤器,以自动检查它们是否
目前,我使用AppController扩展了\ lithium \ action \ Controller,并在其中定义了添加,更新和删除操作。 我的AppController中还有一个布尔函数,用于检查相应的pageInstanceID是否在会话中。
以下是我的代码:
public function isNotPostBack() {
// pull in the session
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageInstanceID = uniqid('', true);
$this->set(compact('pageInstanceID'));
$pageInstanceIDs[] = $pageInstanceID;
Session::write('pageInstanceIDs', $pageInstanceIDs);
// checks if this is a save operation
if ($this->request->data){
$pageInstanceIDs = Session::read('pageInstanceIDs');
$pageIDIndex = array_search($this->request->data['pageInstanceID'], $pageInstanceIDs);
if ($pageIDIndex !== false) {
// remove the key
unset($pageInstanceIDs[$pageIDIndex]);
Session::write('pageInstanceIDs', $pageInstanceIDs);
return true;
}
else
return false;
} else {
return true;
}
}
public function add() {
if (!$this->request->is('post') && exist($this->request->data())) {
$msg = "Add can only be called with http:post.";
throw new DispatchException($msg);
}
}
然后在我的控制器中,我从AppController继承并执行如下操作:
public function add() {
parent::add();
if (parent::isNotPostBack()){
//do work
}
return $this->render(array('layout' => false));
}
这将确保表单使用POST并未双重提交(后退按钮或单击快乐用户)。这也有助于防止XSS。
我知道有一个插件,但我希望将其作为过滤器实现,以便我的控制器方法更清晰。以这种方式实现,我的操作中唯一的代码是// do work部分和return语句。
答案 0 :(得分:2)
你应该从lithium\action\Dispatcher::run()
上的过滤器开始,这里有一些伪代码。如果没有看到parent::isNotPostBack()
方法,就无法帮助太多,但这会让你走上正轨。
<?php
use lithium\action\Dispatcher;
Dispatcher::applyFilter('run', function($self, $params, $chain) {
$request = $params['request'];
// Request method is in $request->method
// Post data is in $request->data
if($not_your_conditions) {
return new Response(); // set up your custom response
}
return $chain->next($self, $params, $chain); // to continue on the path of execution
});
答案 1 :(得分:2)
首先,使用集成的CSRF(XSRF)保护。
RequestToken类创建加密安全的令牌和密钥,可用于验证客户端请求的真实性。
- http://li3.me/docs/lithium/security/validation/RequestToken
以这种方式检查CSRF令牌:
if ($this->request->data && !RequestToken::check($this->request)) {
/* do your stuff */
}
您甚至可以通过is()
$this->request->is('post');
过滤器(针对该用例)的问题在于它们非常通用。因此,如果您不想将所有操作都写为可过滤的代码(这可能会让人感到痛苦和过度杀伤),那么您必须找到一种方法来定义哪种方法阻止了什么并过滤了Dispatcher::_call
。
答案 2 :(得分:0)
对于CSRF保护,我使用类似于greut的建议。
我在extensions/action/Controller.php
protected function _init() {
parent::_init();
if ($this->request->is('post') ||
$this->request->is('put') ||
$this->request->is('delete')) {
//on add, update and delete, if the security token exists, we will verify the token
if ('' != Session::read('security.token') && !RequestToken::check($this->request)) {
RequestToken::get(array('regenerate' => true));
throw new DispatchException('There was an error submitting the form.');
}
}
}
当然,这意味着您还必须将以下内容添加到文件顶部:
use \lithium\storage\Session;
use lithium\security\validation\RequestToken;
use lithium\action\DispatchException;
有了这个,我不必反复检查CSRF。
答案 3 :(得分:0)
我通过将\lithium\action\Controller
子类化为app\controllers\ApplicationController
(摘要)并将过滤器应用于invokeMethod()
,在最近的项目中实现了类似的功能,因为这就是调度程序调用操作方法的方式。这是相关的块:
namespace app\controllers;
class ApplicationController extends \lithium\action\Controller {
/**
* Essential because you cannot invoke `parent::invokeMethod()` from within the closure passed to `_filter()`... But it makes me sad.
*
* @see \lithium\action\Controller::invokeMethod()
*
* @param string $method to be invoked with $arguments
* @param array $arguments to pass to $method
*/
public function _invokeMethod($method, array $arguments = array()) {
return parent::invokeMethod($method, $arguments);
}
/**
* Overridden to make action methods filterable with `applyFilter()`
*
* @see \lithium\action\Controller::invokeMethod()
* @see \lithium\core\Object::applyFilter()
*
* @param string $method to be invoked with $arguments
* @param array $arguments to pass to $method
*/
public function invokeMethod($method, array $arguments = array()) {
return $this->_filter(__METHOD__, compact('method', 'arguments'), function($self, $params){
return $self->_invokeMethod($params['method'], $params['arguments']);
});
}
}
然后,您可以使用applyFilter()
内的_init()
在您的方法上运行过滤器。您可以选择将$method
更改为_filter(__METHOD__, . . .)
,而不是检查每个过滤器中的_filter($method, . . .)
,但我们选择保留更通用的过滤器。