【问题标题】:Invalid token with Joomla custom componentJoomla 自定义组件的令牌无效
【发布时间】:2012-12-26 11:17:21
【问题描述】:

我正在构建一个自定义 Joomla 组件,并将它添加到我的模板 (default.php) 文件中的表单中(它使用的是 HTTP POST):

echo JHTML::_( 'form.token' ); //add hidden token field to prevent CSRF vulnerability

然后我检查控制器中的令牌:

JRequest::checkToken() or die( 'Invalid Token' );

但无论我做什么,我都会得到一个无效的令牌。当我在 html 页面上查看源代码时,我已经验证了在我的表单中创建了一个带有令牌的隐藏类型。我也验证了,在控制器中,token的值是一样的:

print_r(JUtility::getToken());

那么,如果令牌是相同的值,为什么它会以 Invalid Token 消息退出?

编辑:我没有提到一个关键部分。我的表单是在一个单独的 js 文件中使用 jquery ajax 处理的,该文件添加到我的 view.html.php 中。这是 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

【问题讨论】:

  • 您的表单是通过 HTTP GET 还是通过 POST 提交的?
  • @Jim DeLaHunt 这是 HTTP POST
  • @Tom:我已经更新了答案。看看,如果它不起作用,请告诉我。

标签: joomla joomla2.5


【解决方案1】:

以防将来使用:在 Joomla 上! 3.x JUtility::getToken() 已替换为 JSession::getFormToken()

请看这里:http://api.joomla.org/cms-3/classes/JSession.html#method_getFormToken

【讨论】:

    【解决方案2】:

    您似乎没有在 ajax 请求中传递令牌值。这就是您收到此错误的原因。

    你可以—— 1)像这样将令牌附加到网址

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

    并且在 url 中而不是调用 token 你可以调用 getToken()

    url: 'index.php?option=com_recordings&task=deletevideos&format=raw'+getToken()+'=1'
    

    希望这会奏效。

    【讨论】:

    • 完美,谢谢。添加为函数解决了当您使用addScript 时,addScriptDeclaration js 代码未按正确顺序应用的问题。我还必须使用JSession::checkToken('request') or jexit( JText::_( 'Invalid Token' ) );(或JRequest 而不是JSession)。仅当您输入request 时,它才会出于某种原因起作用。这使我的代码至少可以工作,但是我在测试以验证是否引发了 Invalid token 错误时遇到了问题...我想我将把它留给我的下一个 SO 问题 =\
    【解决方案3】:

    初始代码的明显问题是您没有将令牌传递给控制器​​。

    data: {checkedarray:checked} 可能只包含您要删除的 ID 数组。

    Irfan 版本是最容易实现的,它应该可以工作。我设法让它工作。

    这是gist with the working code(请注意,这不是生产就绪代码,只是为了测试令牌问题)。但我已经对其进行了测试,它对我有用。

    【讨论】:

    • 谢谢,我的 jquery ajax 函数在一个单独的 js 文件中,所以我不能在这里使用 php。我需要以某种方式将令牌传递给它...查看更新后的帖子。
    • 嗯,你不远了,只需要添加类似:data: {checkedarray:checked, token:token}.
    【解决方案4】:

    尝试使用

    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 方法。因为他传递了用户名(在他的情况下)和 URL 中的令牌,正如您在他的 AJAX 函数的第三行中看到的那样

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

    无论哪种方式,它都可能需要对您的模型进行一些调整 - 因为您传递了多个变量 - 尽管这应该不难做到。希望这会有所帮助!

    【讨论】:

      【解决方案5】:

      如果表单数据提交为$_GET

      JRequest::checkToken('get') or jexit( 'Invalid Token' );;
      

      如果表单数据提交为$_POST

      JRequest::checkToken('post') or jexit( 'Invalid Token' );;
      

      你可以在下面使用哪个是首选的

      JRequest::checkToken('request') or jexit( 'Invalid Token' );
      

      Read more

      【讨论】:

      • 感谢您查看,但根据docs,帖子是默认的(我正在使用)。反正我试过了,没有运气。最后一个我也试过了,但也没有用(我假设你的意思是JRequest 而不是Request,但都试过了,以防万一)。我相信request 只涵盖发布和获取。还有其他想法吗?
      • 错字应该是JRequest。顺便将 action="index.php?=1" 附加到您的表单中并查看。你知道有时 Joomla 会做一些奇怪的事情。让我知道会发生什么。
      • 我开始看到一个我没有提到的难题的关键部分。该表单使用 jquery AJAX 发布请求进行处理。我遇到了这个post,它可能适用......虽然很旧。有这方面的经验吗?
      猜你喜欢
      • 2017-04-16
      • 1970-01-01
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2017-12-19
      • 2016-09-27
      • 1970-01-01
      相关资源
      最近更新 更多