Quelle est la meilleure façon de gérer les jetons expirés dans laravel 5.
Je veux dire que j'ai une page et qu'elle contient des liens qui exécutent des requêtes ajax. Ils fonctionnent bien lorsque la page est chargée, mais lorsque j'attends un moment, une erreur TOKEN MISMATCH apparaît.
Maintenant, je dois rafraîchir la page pour que cela fonctionne à nouveau. MAIS, je ne veux pas actualiser la page. Je veux un moyen d'actualiser le jeton ou un autre travail pour le réparer.
J'espère que tu as compris mon point.
un moyen de contourner ce problème est d’obtenir le nouveau jeton à chaque fois, sinon vous irez à l’encontre du but du jeton csrf:
<html>
<head>
<meta name="csrf_token" content="{{ csrf_token() }}">
</head>
<body>
<script type="text/javascript">
var csrfToken = $('[name="csrf_token"]').attr('content');
setInterval(refreshToken, 3600000); // 1 hour
function refreshToken(){
$.get('refresh-csrf').done(function(data){
csrfToken = data; // the new token
});
}
setInterval(refreshToken, 3600000); // 1 hour
</script>
</body>
</html>
Dans les itinéraires laravel
Route::get('refresh-csrf', function(){
return csrf_token();
});
Je m'excuse en cas d'erreur de syntaxe, je n'ai pas utilisé jquery depuis longtemps, mais je suppose que vous avez l'idée
Je combine 2 choses pour ce cas:
1. Augmenter la durée de la session
//In config/session.php replace this:
'lifetime' => 120
//with:
'lifetime' => 360
La durée de vie par défaut de Laravel 5 est de 120 (minutes), vous pouvez la modifier à votre guise, par exemple 360 (6 heures).
2. Attraper l'exception et afficher un message d'erreur
//In app/Exceptions/Handler.php replace this:
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
}
return parent::render($request, $e);
}
//with:
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
}
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return redirect('/')->withErrors(['token_error' => 'Sorry, your session seems to have expired. Please try again.']);
}
return parent::render($request, $e);
}
Donc, fondamentalement, vous redirigez l'utilisateur vers la racine "/" (vous pouvez le changer pour n'importe quel chemin) avec un message d'erreur et vous devez le faire sur cette page pour afficher le message d'erreur
@if ($errors->has('token_error'))
{{ $errors->first('token_error') }}
@endif
Augmentez la lifetime
de vos sessions. Vous pouvez le faire en modifiant le fichier config/session.php
dans votre configuration laravel.
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option.
|
*/
'lifetime' => 120,
Le meilleur moyen de gérer cette exception est avec App\Exceptions\Handler.php
.
public function render($request, Exception $e) {
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return Redirect::back()->withErrors(['session' => 'Désolé, votre session semble avoir expiré. Veuillez réessayer.']);
}
return parent::render($request, $e);
}
et où que vous vouliez montrer ce message (dans toutes vos pages contenant csrf_token
), ajoutez cette pièce:
<div>
@if(count($errors)>0)
@foreach($errors->all() as $error)
<ul>
<li>{{$error}}</li>
</ul>
@endforeach
@endif
</div>
Je sais que ce n'est pas la meilleure solution, mais l'une des plus simples. Il suffit de désactiver la protection CSRF pour cette page, où l'utilisateur passe beaucoup de temps . Par exemple, sur mon site, ils peuvent écrire un article pendant des heures sur une page. Et il est très frustrant de ne pas pouvoir sauvegarder un article en raison de la protection du CSRF.
Ce ne sont pas des solutions de contournement que je n'aime pas trop ..
https://laravel.com/docs/5.5/csrf
Ajouter simplement un enregistrement sur $ sauf array sur VerifyCsrfToken Middleware avec votre uri que vous souhaitez exclure .Veuillez prendre en compte, cela ne doit être fait que dans des cas spécifiques.
C’est la meilleure solution pour moi ... Simple et comme tout (ou presque) sur Laravel, ils y ont déjà pensé. ;)
Je pense que la meilleure option est de prendre la configuration de la durée de vie du fichier config/session.php, puis la valeur de la durée de vie multipliée par 60 * 1000 dans le code javascript. Utilisez la fonction d'assistance config () fournie par laravel, elle pourrait ressembler à ceci:
<script type="text/javascript">
var timeout = ({{config('session.lifetime')}} * 60) * 1000;
setTimeout(function() {
//reload on current page
window.location = '';
}, timeout);
</script>
un moyen court et rapide .... pour gérer les requêtes ajax, à l'expiration du jeton: ajoutez ce script à la fin de la mise en page principale ou de votre document
$(window).load(function(){
$.ajaxSetup({
statusCode: {
419: function(){
location.reload();
}
}
});
});
et pour gérer les requêtes http lorsque le jeton arrive à expiration, créez 419.blade.php dans le chemin suivant:\resources\views\errors et ajoutez ce script:
<script type="text/javascript">
//reload on current page
window.location = '';
</script>
Circuler sur le jeton est généralement accepté comme une approche terrible, mais l’utilisation des minuteries js mentionnées ci-dessus pose également des problèmes. js seetTimeout/setInterval n'est pas fiable lorsque l'onglet du navigateur n'est pas mis en évidence, minimisé ou, dans le cas de nombreux utilisateurs, que leur ordinateur portable/périphérique est en veille/fermé, etc.
Un meilleur itinéraire pourrait consister à utiliser un minuteur js pour recalculer le "temps de mourir" d'un horodatage défini dans un cookie (ou une balise méta pour les utilisateurs exigeants du GDPR sans cookie). cet horodatage correspondra à l'heure de la fin de la session et sera mis à jour à chaque actualisation de la page. Ainsi, peu importe ce que le navigateur/l'appareil faisait ou ne faisait pas en votre absence ET il sera toujours précis pour ceux dont le message est «Gardez-moi connecté», etc.
Le problème suivant est de savoir quoi faire au lieu de réinitialiser automatiquement le jeton. Présentez à l'utilisateur un formulaire de "reconnexion" (modal/contextuel) qui ajaxe le nouveau jeton à la page, comme indiqué ci-dessus.
Vous pouvez essayer Le paquet Caffeine for Laravel il définit un intervalle, puis actualise le jeton comme suggéré dans certaines réponses;