Invalid token with Joomla custom component

2019-04-15 11:20发布

问题:

I'm building a custom Joomla component and I added this to my form in my template (default.php) file (it is using a HTTP POST):

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

Then I check the token in my controller with:

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

But no matter what I do I get an Invalid Token. I have verified that a hidden type with a token is created in my form when I view sources on the html page. I also verified, in the controller, the value of the token is the same:

print_r(JUtility::getToken());

So if the token is the same value, why on earth is it exiting with an Invalid Token message?

EDIT: There is a key piece I failed to mention. My form is processed with jquery ajax in a separate js file that is added in my view.html.php. This is what the ajax POST looks like:

jQuery.ajax({
    type: 'POST',
    url: 'index.php?option=com_recordings&task=deletevideos&format=raw',
    data: {checkedarray:checked},
    success: function(data){
               //delete row
    }
});

The controller processes this:

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

This then goes to the model that does the DB update. I saw this old post that might be relevant. It is not clear to me how/where I generate the token and where/how I validate that token. The post seems quite involved as it checks against users as well which I don't think is needed in my case. Or maybe I misunderstand?

EDIT #2

Okay so the token is missing and I need to pass it into my js file. So I thought I could add this to my 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");

I have to put this in the document ready function because apparently addScriptDeclaration does not put anything ahead of my recordings.js file. Then pass the token into the ajax call:

jQuery.ajax({
    type: 'POST',
    url: 'index.php?option=com_recordings&task=deletevideos&format=raw'+token+'=1',
    data: {checkedarray:checked},
    success: function(data){
               //delete row
    }
});

Apparently I'm not doing this right as I get this error: ReferenceError: token is not defined.

回答1:

It does not seem that you are passing token value in the ajax request.And that's why you are getting this error.

You can - 1) append token to the url like this

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

2) Or send the whole form using Serialize.

EDIT 2:- You can create a function called getToken like this-

 $addtokenjs = 'function getToken() {
                    var token="'.$addtoken.'";
                    return token;
                    };';

And in url instead of calling token you can call getToken()

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

Hope this will work.



回答2:

Try using

JSession::checkToken() or die( JText::_( 'Invalid Token' ) );

rather than JRequest. The reason I like JSession more is because it guarentees Joomla 2.5/3.0 compatibility without having to think about JRequest being deprecated. In Joomla 2.5 the function uses JRequest and in 3.0 uses JInput.


EDIT

For the AJAX ou actually need to pass the data across with the POST. Your data is currently just going to be the checkedarray:checked i.e. the checked data and NOT the token in the AJAX request. You'll need to pass the data across with serialize if you wish to use the POST method. However note that serialize will place the data in the URL anyhow. You can then process this token with

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

Just for completelness the link you have given uses the GET method. In that he's passed across the username (in his case) and the token in the URL as you can see on the third line of his AJAX function

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
}

and then after this is it is trivial to process just using

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

Either way its probably going to involve some tweaking to your model - as your passing across more than 1 variable - although it shouldn't be hard to do. Hope this helps!



回答3:

If the form data is submitted as $_GET

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

If the form data is submitted as $_POST

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

Else you can use below which is preferred

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

Read more



回答4:

The obvious problem with your initial code is that you are not passing the token to the controller.

data: {checkedarray:checked} probably contains just an array of IDs you want to delete.

Irfan version is the easiest to implement and it should work. I've managed to make it work.

Here is a gist with the working code (please note that this is not production ready code, it's just to test the token problem). But I've tested it and it works for me.



回答5:

Just in case of future use: On Joomla! 3.x JUtility::getToken() has been replaced with JSession::getFormToken().

See here: http://api.joomla.org/cms-3/classes/JSession.html#method_getFormToken