Handling expired token in Laravel

后端 未结 13 2621
情话喂你
情话喂你 2020-11-29 00:30

What is the best way to handle expired tokens in laravel 5.

I mean I have a page and it has some links which perform ajax requests. They work fine when the page is

相关标签:
13条回答
  • 2020-11-29 01:21

    I combine 2 things for this case:

    1. Increase session lifetime

    //In config/session.php replace this:
    
    'lifetime' => 120
    
    //with:
    
    'lifetime' => 360
    

    Laravel 5 default lifetime is 120 (minutes), you can change it to whatever value you like, for example 360 (6 hours)

    2. Catch the exception and display an error message

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

    So basicaly you redirect the user to the root "/" (you can change this to any path you want) with an error message and on that page you have to do this to display the error message:

    @if ($errors->has('token_error'))
        {{ $errors->first('token_error') }}
    @endif
    
    0 讨论(0)
  • 2020-11-29 01:21

    try this in your main layout file

    @guest
        <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
        <meta http-equiv="Pragma" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta http-equiv="refresh" content="{{config('session.lifetime') * 60}}">
    @endguest
    
    0 讨论(0)
  • 2020-11-29 01:22

    a work around for it, is to actually get the new token every certain time, otherwise you are defeating the purpose of the 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 routes

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

    I apologize in case of any syntax errors, haven't used jquery for long time, but i guess you get the idea

    0 讨论(0)
  • 2020-11-29 01:23

    According to the docs:

    Laravel automatically generates a CSRF "token" for each active user session managed by the application.

    This means, for any individual the csrf code is the same for any page that the user visits. It becomes invalid once your session expires. Thus if you set the lifetime to 1 week, CSRF token will only expire after 1 week.

    This can achieved like this in config/session.php:

     /*
        |--------------------------------------------------------------------------
        | 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' => 60 * 24 * 7, // Set session lifetime to 1 week
    
        'expire_on_close' => true,
    

    Why I dont like any of the above answers:

    1. Answer from UX Labs:

    Keeps the session forever alive and recreates a new CSRF token after a fixed time. This is an issue if the user has multiple taps open. Everytime one tap refreshes the CSRF token, all the other tabs become invalid.

    1. Answer from Ryan

    This answer is better, because it does not change the CSRF token, so multiple tabs are not effected. It simply keeps the session alive with making a js call after a fixed time with setInterval. However, setInterval does not work while the PC goes to sleep. So the session may expire when the PC goes to sleep, which is also a likly scenario. Therefore, instead of trying to keep the session alive by js-calls,just increase lifetime.

    1. Answer from paulalexandru

    Displaying an error when session is timed out is okay, but it would be better if the issue never happens. Setting lifetime to 6h is not enough, because its likly that a tab may be open for a couple of days.

    1. Other answers

    All the other answers propose to disable CSRF for the route in questions, but this is of course no option, because it creates a big security risk.

    0 讨论(0)
  • 2020-11-29 01:23

    I think the best option is to take the lifetime configuration of the config/session.php file, then the lifetime value multiplied by 60 * 1000 in the javascript code. Use helper function config() provided by laravel, it might look like this:

    <script type="text/javascript">
        var timeout = ({{config('session.lifetime')}} * 60) * 1000;
        setTimeout(function() {
            //reload on current page
            window.location = '';
        }, timeout);
    </script>
    
    0 讨论(0)
  • 2020-11-29 01:28

    You may try Caffeine for Laravel package it set an interval then it refresh the token like suggested in some answers also it will be added automatically in every form having csrf token

    0 讨论(0)
提交回复
热议问题