我正在构建一个自定义的Joomla组件,我在我的模板(default.php)文件中添加了这个(它正在使用HTTP POST):
echo JHTML::_( 'form.token' ); //add hidden token field to prevent CSRF vulnerability
然后我用控制器检查控制器中的令牌:
JRequest::checkToken() or die( 'Invalid Token' );
但无论我做什么,我都会得到一个无效的令牌。我已经验证了当我在html页面上查看源时,在我的表单中创建了带有令牌的隐藏类型。我还验证了,在控制器中,令牌的值是相同的:
print_r(JUtility::getToken());
因此,如果令牌是相同的值,为什么它会以无效令牌消息退出?
编辑:我没有提到一个关键部分。我的表单使用jquery ajax在我的view.html.php中添加的单独的js文件中处理。这就是ajax POST的样子:
jQuery.ajax({
type: 'POST',
url: 'index.php?option=com_recordings&task=deletevideos&format=raw',
data: {checkedarray:checked},
success: function(data){
//delete row
}
});
控制器处理:
function deletevideos()
{
$video_list = JRequest::getVar('checkedarray', 0, 'post', 'array');
//print_r(JUtility::getToken());
JRequest::checkToken() or jexit( 'Invalid Token' );
$model = &$this->getModel();
return $model->setDeleteVideos($video_list);
}
然后转到进行数据库更新的模型。我看到了可能相关的旧post。我不清楚如何/在哪里生成令牌以及我在何处/如何验证该令牌。该帖子似乎非常复杂,因为它检查用户,我认为在我的情况下不需要。或者我误解了?
编辑#2
好的,所以令牌丢失了,我需要将它传递给我的js文件。所以我想我可以将它添加到我的view.html.php:
$addtoken = JUtility::getToken();
$addtokenjs = 'jQuery(function() {
var token="'.$addtoken.'";
});';
$doc->addScriptDeclaration( $addtokenjs );
$doc->addScript(JURI::base()."components/com_recordings/js/recordings.js");
我必须把它放在文档就绪函数中,因为显然addScriptDeclaration没有把任何东西放在我的recordings.js文件之前。然后将令牌传递到ajax
电话:
jQuery.ajax({
type: 'POST',
url: 'index.php?option=com_recordings&task=deletevideos&format=raw'+token+'=1',
data: {checkedarray:checked},
success: function(data){
//delete row
}
});
显然我没有这样做,因为我收到此错误:ReferenceError: token is not defined
。
答案 0 :(得分:4)
您似乎没有在ajax请求中传递令牌值。这就是您收到此错误的原因。
你可以 - 1)像这样将URL添加到URL
url: 'index.php?option=com_recordings&task=deletevideos&format=raw&'. JUtility::getToken() .'=1'
2)或使用Serialize发送整个表单。
编辑2: - 您可以像这样创建一个名为getToken的函数 -
$addtokenjs = 'function getToken() {
var token="'.$addtoken.'";
return token;
};';
在网址中,您可以拨打token
getToken()
url: 'index.php?option=com_recordings&task=deletevideos&format=raw'+getToken()+'=1'
希望这会奏效。
答案 1 :(得分:2)
尝试使用
JSession::checkToken() or die( JText::_( 'Invalid Token' ) );
而不是JRequest。我更喜欢JSession的原因是因为它保证了Joomla 2.5 / 3.0兼容性,而不必考虑JRequest被弃用。在Joomla 2.5中,该函数使用JRequest,而在3.0中使用JInput。
修改强>
对于AJAX,您实际上需要使用POST
传递数据。您的数据目前只是checkedarray:checked
,即已检查的数据,而不是AJAX请求中的令牌。如果您希望使用POST
方法,则需要使用serialize传递数据。但请注意,序列化无论如何都会将数据放在URL中。然后,您可以使用
// Check for request forgeries using one of either JRequest of JSession
JRequest::checkToken( 'get' ) or jexit( 'Invalid Token' );
//Alternative
JSession::checkToken( 'get' ) or jexit( 'Invalid Token' );
为了完整,您提供的链接使用GET方法。因为你可以在他的AJAX函数的第三行看到他传递的用户名(在他的情况下)和URL中的标记
function check_username(username, token) {
var url = 'index.php?option=com_user&task=check_user';
data = 'username=' + username + '&' + token; //TOKEN INSERTED INTO URL HERE
$.ajax({
type: "GET",
url: url,
data: data,
success: function(xml) {
var result = $(xml).find('response').text();
if (result == 'found') {
alert( 'Please select a different username, ' + username + ' already exists' );
}
}
}); // ajax
}
然后在此之后使用
进行处理是微不足道的// Check for request forgeries using one of either JRequest of JSession
JRequest::checkToken( 'get' ) or jexit( 'Invalid Token' );
//Alternative
JSession::checkToken( 'get' ) or jexit( 'Invalid Token' );
无论哪种方式,它可能会涉及到你的模型的一些调整 - 当你传递超过1个变量 - 虽然它应该不难做到。希望这有帮助!
答案 2 :(得分:1)
如果表单数据提交为$_GET
JRequest::checkToken('get') or jexit( 'Invalid Token' );;
如果表单数据提交为$_POST
JRequest::checkToken('post') or jexit( 'Invalid Token' );;
否则,您可以使用下面的首选
JRequest::checkToken('request') or jexit( 'Invalid Token' );
答案 3 :(得分:1)
初始代码的明显问题是您没有将令牌传递给控制器。
data: {checkedarray:checked}
可能只包含您要删除的ID数组。
Irfan版本是最容易实现的,它应该可以工作。我成功地使它成功了。
这是gist with the working code(请注意,这不是生产就绪代码,只是为了测试令牌问题)。但我测试了它,它对我有用。
答案 4 :(得分:1)
以防将来使用:在Joomla上! 3.x JUtility::getToken()
已替换为JSession::getFormToken()
。
见这里:http://api.joomla.org/cms-3/classes/JSession.html#method_getFormToken