web-dev-qa-db-fra.com

Comment vérifier SESSION en javascript

Je développe un composant et j'utilise des appels ajax pour effectuer certaines tâches dans l'interface. Je suis arrivé à un problème lorsque la session est expirée et je ne veux pas utiliser keepalive pour le résoudre.

Dans l'interface j'ai une vue de liste. Et il y a quelques boutons qui effectuent des tâches en utilisant des requêtes ajax.

Par exemple :

$('#resetData').on('click', function (e) {
  e.preventDefault();
  var token = jQuery("#token").attr("name");
  var itemId = $(this).attr('data-id');
$.ajax({
  method: 'POST',
  cache: false,
  dataType: "json",
  data: { [token]: "1", id: itemId},
  url: 'index.php?option=com_contract&task=contract.resetData'
}).success(function (r) {
  console.log('Response :');
  console.log(r);
  if (r.responseText) {
    UIkit.modal.alert(r.responseText).then(function () {
      window.location.reload();
    });
  }
  if (r.message) {
    UIkit.modal.alert(r.message).then(function () {
      window.location.reload();
    });
  }
}).error(function (err) {
  console.log(err);
  UIkit.modal.alert('<div class="alert alert-error">' + err + '</div>').then(function () {
    return;
  });
}).complete(function (r) {
  console.log(r.responseText);
});

Lorsque la session a expiré, dans mon contrôleur principal, je redirige vers la page de connexion. JFactory::getApplication()->redirect(JURI::base() . 'index.php?option=com_users&view=login', $error, 'error'); //redirect to login page

Cela signifie que le code HTML de trou est renvoyé dans la réponse Ajax et que lorsque je affiche la réponse, je reçois un [object object] Au lieu d'une erreur lisible par l'homme.

Je suppose que je dois trouver un moyen de vérifier si la session a expiré lorsque l'événement click se déclenche et génère une alerte avant de passer l'appel Ajax.

Est-il possible de vérifier la JSESSION en javascript ou tout autre moyen de la résoudre?

3
mixahlos

Je peux imaginer de vérifier la session avant d’allumer l’appel ajax ci-dessus, vous effectuez un précédent appel ajax vers une autre fonction de com_contract/controller (tâche = votre nouvelle fonction de vérification de session. So: url: ... com_contract/task = checkSession) où vous créez une fonction, quelque chose comme:

public function checkSession() 
{
  try
    {    
      $session1 = JFactory::getSession();
      $isActive = $session1->isActive();
      $sessionState = $session1->getState();
      echo new JResponseJson($isActive, $sessionState);
    }
  catch(Exception $e)
    {
      echo new JResponseJson($e);
    }
}

Je viens de créer cette fonction rapidement ici, donc des erreurs peuvent y figurer et peuvent également être améliorées, mais c’est ainsi que je commencerais à vérifier la session via ajax.

L'autre implication serait, selon moi, que si une session est expirée, le jeton pourrait être invalide pendant cet appel. Je n'ai pas essayé cela, il faut donc vérifier si l'appel ajax peut être envoyé avec le jeton (à partir d'une session expirée. Cela ne semble pas trop logique).

C'est précisément pour cette raison (jetons expirés) que j'ai suggéré plus tôt de garder la session active, au lieu d'autres solutions sur les sessions.

Quelques réflexions supplémentaires sur ce sujet (puisque ce sujet sera abordé plusieurs fois ici)

Si vous essayez de passer un appel ajax avec un jeton de session expiré, vous obtiendrez toujours une réponse "jeton invalide". Par conséquent, l'appel ajax échouera de toute façon. Il est donc préférable d'effectuer une redirection en javascript si la réponse est "invalide". jeton 'en raison d'une session expirée ou d'une réponse non valide (simplement un appel ajax ayant échoué). Ensuite, la fonction check session pourrait être étendue à quelques lignes, par exemple, mais son but n’est probablement pas valable dans ce cas:

public function checkSession() 
{
    if (! JSession::checkToken())
    {
        echo new JResponseJson('invalid token');
        // jexit( 'Invalid Token' );
    }
    else
    {
      try
        {    
          $session1 = JFactory::getSession();
          $isActive = $session1->isActive();
          $sessionState = $session1->getState();
          echo new JResponseJson($isActive, $sessionState);
        }
      catch(Exception $e)
        {
          echo new JResponseJson($e);
        }
    }
}

Je voulais ajouter ceci à ce sujet. Mais sans cette fonction relativement redondante, toute réponse de jeton non valide devrait déclencher une redirection dans le javascript, de sorte que la vérification de l'état de la session n'est pas vraiment nécessaire ici. Au moins, pour le moment, je ne vois pas la raison de cela.

N AUTRE POINT IMPORTANT CONCERNANT AJAX CALLS

En raison de la théorie et des raisons susmentionnées, la solution de ce problème n’est que 1 appel ajax, pas deux (en raison des complications possibles de la structure des promesses javascript). Comme le problème a été mentionné dans les commentaires. Ce qui signifie que le contrôle de jeton doit simplement être placé dans la fonction de votre contrôleur d'origine (resetData). Donc, vous n'avez pas besoin d'utiliser une autre fonction pour vérifier le jeton. Nous revenons simplement à l'essentiel ici. Votre fonction originale de Joomla devrait bien sûr commencer avec la vérification des jetons. Si elle n’échoue pas avec un jeton non valide, elle peut être complétée.

public function resetData()
{
    if (! JSession::checkToken())
    {
        echo new JResponseJson('invalid token');
        die('my messages';
    }
    elseif ( JSession::checkToken())
    {

        // all of your resetData function steps

    }
}

Ou encore plus simple, comme cela est donné dans toutes ces fonctions de Joomla:

public function resetData()
{
    JSession::checkToken() or die('my messages');
    // then all of your resetData function steps...
    // what is giving back different responses
}

Donc, ce serait un bon début pour toute fonction Joomla appelée avec ajax.

3
Zollie

Pour obtenir l'état de la session, vous pouvez utiliser les éléments suivants:

JFactory::getSession()->getState();

Je ne suis pas sûr si ce script est en ligne ou un fichier séparé. S'il est en ligne, vous pouvez simplement ajouter ce qui suit à votre Javascript:

var sessionState = '<?php echo JFactory::getSession()->getState(); ?>';
if (sessionState === 'expired') {
    // redirect to login page
}

D'un autre côté, l'utilisation de .success() et .error() est déconseillée dans jQuery. Veuillez utiliser .done() et .fail(). De plus, juste pour que vous sachiez que .then() ne fonctionnera pas dans IE11.

2
Lodder

bien après l’aide précieuse de @Zollie, je posterai la réponse et le code de travail pour aider les autres.

Un exemple du fichier modèle:

    <form action="<?php echo JRoute::_('index.php?option=com_contract&view=contracts'); ?>" id="adminForm" method="post" name="adminForm">
      <?php if (!empty($this->items)) { ?>
        <div class="contractList items">
          <?php foreach ($this->items as $item) {?>
            <div class="contract item">
              <h3> <?php echo $item->title; ?></h3>
              <p> <?php echo $item->text; ?></p>
              <div class="actions">
                <a class="action" href="#" data-action="unpublish"><?php echo JText::_('COM_CONTRACT_UNPUBLISH_ITEM');?></a>
                <a class="action" href="#" data-action="resetData"><?php echo JText::_('COM_CONTRACT_RESTET_ITEM');?></a>
                    <input type="checkbox" class="uk-checkbox" name="cid[<?php echo $i; ?>]" id="cb<?php echo $i; ?>" value="<?php echo $item->id; ?>" onclick="Joomla.isChecked(this.checked);">
              </div>
           </div>
          <?php } ?>
        </div>
      <? } ?>
      <input type="hidden" name="task" value=""/>
      <?php echo '<input id="token" type="hidden" name="' . JSession::getFormToken() . '" value="1" />'; // We need the token this way in order to get it to the javascript. ?>
    </form>

Le javascript

<script type="text/javascript">
  function checkSession(caller) {
    var token = jQuery("#token").attr("name");
    $.ajax({
      method: 'POST',
      dataType: "json",
      data: {[token]: "1"},
      url: 'index.php?option=com_contract&task=contracts.checkSession'
    }).done(function (r) {
      // Since we had a success call, means that the session is active so we can continue to call the actual task.
      var data = {};
      data.id = $(caller).closest("div.actions").find("input[type='checkbox']").val();
      data.action = $(caller).attr('data-action');
      ajaxSubmit('index.php?option=com_contract&task=contracts.' + data.action, token, data);
    }).fail(function (err) {
      // If there the call fails, means there is no active session.
      UIkit.modal.alert('<div class="alert alert-error">' + Joomla.JText._('SESSION_TIMEOUT') + '</div>').then(function () {
        window.location.reload(); // reload to get to the login page.
      });
    });
  }

  function ajaxSubmit(Url, token, data) {
    $.ajax({
      method: 'POST',
      dataType: "json",
      data: {[token]: "1", data},
      url: Url
    }).done(function (r) {
        window.location.reload();
      }
      if (r.message) {
        UIkit.modal.alert(r.message).then(function () {
          window.location.reload();
        });
      }
    }).fail(function (err) {
      UIkit.modal.alert('<div class="alert alert-error">' + err + '</div>').then(function () {
        return;
      });
    });
  }
$(document).ready(function () {
  $('.action').on('click', function (e) {
    e.preventDefault();
    checkSession(this);
  });
});
</script>

La fonction du contrôleur.

Dans la fonction checkSession, je me suis rendu compte que peu importe ce que vous retournez, car si la fonction est appelée, la session est toujours active.

  public function checkSession() {
    if (!JSession::checkToken()) {
      echo new JResponseJson('invalid token');
      JFactory::getApplication()->close();
    }
  }

J'ai fait de nombreux tests et fonctionne toujours.

2
mixahlos