webentwicklung-frage-antwort-db.com.de

In Laravel ist das Token abgelaufen

Was ist der beste Weg, um abgelaufene Marker in Laravel zu handhaben? 5. 

Ich meine, ich habe eine Seite und einige Links, die Ajax-Anfragen ausführen. Sie funktionieren gut, wenn die Seite geladen ist, aber wenn ich auf etwas warte, erhalte ich einen TOKEN MISMATCH-Fehler. 

Jetzt muss ich die Seite aktualisieren, damit sie wieder funktioniert. ABER ich möchte die Seite nicht aktualisieren. Ich möchte eine Möglichkeit, das Token oder eine andere Arbeitsweise zu aktualisieren, um das Problem zu beheben.

Ich hoffe du hast meinen Punkt verstanden.

29

um dieses Problem zu umgehen, erhalten Sie das neue Token tatsächlich zu jeder Zeit, ansonsten verlieren Sie den Zweck des Csrf-Token:

<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>

In Laravel-Routen

Route::get('refresh-csrf', function(){
    return csrf_token();
});

Ich entschuldige mich bei Syntaxfehlern, habe Jquery lange nicht benutzt, aber ich schätze, Sie haben die Idee

16
UX Labs

Ich kombiniere 2 Dinge für diesen Fall:

1. Lebensdauer der Sitzung erhöhen

//In config/session.php replace this:

'lifetime' => 120

//with:

'lifetime' => 360

Die Standardlebensdauer von Laravel 5 beträgt 120 (Minuten). Sie können den Wert beliebig einstellen, beispielsweise 360 ​​(6 Stunden).

2. Die Ausnahme abfangen und eine Fehlermeldung anzeigen

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

Grundsätzlich leiten Sie den Benutzer mit einer Fehlermeldung zum Stammverzeichnis "/" (Sie können dies in einen beliebigen Pfad ändern) und auf dieser Seite müssen Sie Folgendes tun, um die Fehlermeldung anzuzeigen:

@if ($errors->has('token_error'))
    {{ $errors->first('token_error') }}
@endif
16
paulalexandru

Ich denke, die Antwort von @UX Labs ist irreführend. Und dann scheint der Kommentar von @jfadich völlig falsch zu sein.

Für Laravel 5.4 im Mai 2017 habe ich das Problem folgendermaßen gelöst:

Hier ist eine Antwort, die funktioniert

In web.php:

Route::post('keep-token-alive', function() {
    return 'Token must have been valid, and the session expiration has been extended.'; //https://stackoverflow.com/q/31449434/470749
});

In Javascript aus Ihrer Sicht:

$(document).ready(function () {

    setInterval(keepTokenAlive, 1000 * 60 * 15); // every 15 mins

    function keepTokenAlive() {
        $.ajax({
            url: '/keep-token-alive', //https://stackoverflow.com/q/31449434/470749
            type: 'post',
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        }).then(function (result) {
            console.log(new Date() + ' ' + result + ' ' + $('meta[name="csrf-token"]').attr('content'));
        });
    }

});

Beachten Sie, dass Sie nicht'keep-token-alive' In den Ausschlüssen in VerifyCsrfToken.php Auflisten müssen. Wie @ ITDesigns.eu in einem Kommentar angedeutet hat, ist es für diese Route wichtig, zu überprüfen, ob ein gültiges Token derzeit vorhanden ist und dass der Ablauf nur verlängert werden muss.

Warum dieser Ansatz mein Problem löst

Auf meiner Laravel Site können Benutzer ein Video ansehen (eine Stunde lang), und sie verwendet Ajax, um ihren Fortschritt jede Minute zu veröffentlichen.

Aber viele Benutzer laden die Seite und starten das Video erst viele Stunden später.

Ich weiß nicht, warum sie ihren Browser-Tab so lange offen lassen, bevor sie es ansehen, aber sie tun es.

Und dann habe ich eine Menge TokenMismatch-Ausnahmen in meinen Protokollen (und würde die Daten ihres Fortschritts verpassen).

In session.php Habe ich 'lifetime' Von 120 auf 360 Minuten geändert, aber das war immer noch nicht genug. Und ich wollte es nicht länger als 6 Stunden machen. Daher musste ich diese eine Seite aktivieren, um die Sitzung häufig über Ajax zu verlängern.

So können Sie es testen und sich ein Bild davon machen, wie die Token funktionieren:

In web.php:

Route::post('refresh-csrf', function() {//Note: as I mentioned in my answer, I think this approach from @UX Labs does not make sense, but I first wanted to design a test view that used buttons to ping different URLs to understand how tokens work. The "return csrf_token();" does not even seem to get used.
    return csrf_token();
});
Route::post('test-csrf', function() {
    return 'Token must have been valid.';
});

In Javascript aus Ihrer Sicht:

<button id="tryPost">Try posting to db</button>
<button id="getNewToken">Get new token</button>

(function () {
    var $ = require("jquery");

    $(document).ready(function () {
        $('body').prepend('<div>' + new Date() + ' Current token is: ' + $('meta[name="csrf-token"]').attr('content') + '</div>');
        $('#getNewToken').click(function () {
            $.ajax({
                url: '/refresh-csrf',
                type: 'post',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            }).then(function (d) {
                $('meta[name="csrf-token"]').attr('content', d);
                $('body').prepend('<div>' + new Date() + ' Refreshed token is: ' + $('meta[name="csrf-token"]').attr('content') + '</div>');
            });
        });
        $('#tryPost').click(function () {
            $.ajax({
                url: '/test-csrf',
                type: 'post',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            }).then(function (d) {
                $('body').prepend('<div>' + new Date() + ' Result of test: ' + d + '</div>');
            });
        });


    });
})();

Ändern Sie in session.php Vorübergehend 'lifetime' Zu Testzwecken in einen sehr kurzen Wert.

Dann herumspielen.

Auf diese Weise habe ich gelernt, wie das Laravel Token funktioniert und wie wir wirklich nur erfolgreich POST zu einer CSRF-geschützten Route führen müssen, damit das Token weiterhin funktioniert gültig sein.

16
Ryan

Erhöhen Sie die lifetime Ihrer Sitzungen. Sie können dies tun, indem Sie die config/session.php-Datei in Ihrer Laravel-Konfiguration bearbeiten.

/*
|--------------------------------------------------------------------------
| 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,
1

Am besten behandeln Sie diese Exception mit 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);
    }


und wo immer Sie diese Nachricht anzeigen möchten (in allen Ihren Seiten, die csrf_token enthalten), fügen Sie dieses Stück hinzu:

<div>
@if(count($errors)>0)
    @foreach($errors->all() as $error)
        <ul>
            <li>{{$error}}</li>
        </ul>
    @endforeach
@endif
</div>

0
brahimm

Ich weiß, es ist nicht die beste Lösung, aber eine der einfachsten. Deaktivieren Sie einfach den CSRF-Schutz für diese Seite, auf der der Benutzer viel Zeit verbringt .____ Auf meiner Website können Sie Artikel stundenlang auf eine Seite schreiben. Und es ist sehr frustrierend, wenn Sie Artikel aufgrund des CSRF-Schutzes nicht speichern können.

0
Mantas D

Dies sind alle Problemumgehungen, die ich nicht mag. (Aber ich gebe zu, dass sie funktionieren können.) Ich weiß nicht, da diese Version auf Laravel vorhanden ist, aber es gibt eine Möglichkeit, Seiten von der CSRF-Tokenvalidierung auszuschließen:

https://laravel.com/docs/5.5/csrf

Fügen Sie einfach einen Datensatz zu $ ​​mit Ausnahme des Arrays in VerifyCsrfToken Middleware mit Ihrem URI hinzu, den Sie ausschließen möchten . Bitte berücksichtigen Sie, dass dies nur in bestimmten Fällen erforderlich ist.

Dies ist die beste Lösung für mich ... Einfach und genau wie (fast) alles auf Laravel, haben sie schon darüber nachgedacht. ;)

0
crisleiria

Ich denke, die beste Option ist, die Lifetime-Konfiguration der Datei config/session.php zu übernehmen, dann den Lifetime-Wert mit 60 * 1000 im Javascript-Code zu multiplizieren. Verwenden Sie die Hilfsfunktion config (), die von laravel bereitgestellt wird. Sie könnte folgendermaßen aussehen:

<script type="text/javascript">
    var timeout = ({{config('session.lifetime')}} * 60) * 1000;
    setTimeout(function() {
        //reload on current page
        window.location = '';
    }, timeout);
</script>
0
masdeveloper

ein kurzer und schneller Weg zur Bearbeitung von Ajax-Anforderungen, wenn das Token abläuft: Fügen Sie dieses Skript am Ende des Master-Layouts oder Ihres Dokuments hinzu

$(window).load(function(){
    $.ajaxSetup({
        statusCode: {
            419: function(){
                    location.reload(); 
                }
        }
    });
});

um HTTP-Anforderungen zu bearbeiten, wenn das Token abläuft, erstellen Sie 419.blade.php in diesem Pfad:\resources\views\errors und fügen Sie dieses Skript hinzu:

<script type="text/javascript">
    //reload on current page
    window.location = '';

</script>
0
fatemeh sadeghi

Das Navigieren im Token durch Umkreise wird im Allgemeinen als schrecklicher Ansatz akzeptiert, es gibt jedoch auch Probleme bei der Verwendung von js-Timern, die oben erwähnt wurden. js seetTimeout/setInterval ist unzuverlässig, wenn die Browser-Registerkarte entweder nicht scharfgestellt oder minimiert ist oder wenn viele Benutzer ihren Laptop/Gerät im Ruhezustand/geschlossen usw. haben.

Eine bessere Route könnte sein, einen js-Timer zu verwenden, um die 'time to sterben' aus einem in einem Cookie gesetzten Datumsstempel (oder einem Meta-Tag für Benutzer von GDPR ohne Cookie) neu zu berechnen. Dieser Datumsstempel ist die Zeit (Real Time) der Zeit, in der die Sitzung stirbt und bei jeder Seitenaktualisierung aktualisiert wird. Auf diese Weise spielt es keine Rolle, was der Browser/das Gerät in Ihrer Abwesenheit gemacht hat/was es nicht tat UND es ist immer noch genau für diejenigen, die 'weiter angemeldet bleiben' usw. haben.

Das nächste Problem ist, was zu tun ist, anstatt das Token automatisch neu zu laden - dem Benutzer ein "Re-Login-in" -Form (Modal/Popup) vorzulegen, das das neue Token wie oben erwähnt zur Seite bringt.

0
pSouper

Sie können versuchen, Koffein für Laravel-Paket es wird ein Intervall gesetzt, dann wird das Token aktualisiert, wie in einigen Antworten vorgeschlagen