實作網頁與後端Session Timeout

實作網頁與後端Session Timeout

Timeout的核心部分引用Versatility Werks的程式碼jTimeout.js(程式碼貼於此文章最下方),Html頁面實作則分三部分

jTimeout.js的一些參數設定與功能實作

<script src="your_js_path/jTimeout.js"></script>
<script>
$(function(){
	$.jTimeout({
	  	/* 10分鐘Timeout */
	  	'onClickExtend': function(jTimeout){
	  		window.localStorage.timeoutCountdown = 600
	  		$('#consTime').text( 600 );
	  	},
	  	/* 倒數60秒後不延長則Timeout,秒數設定在jTimeout的secondsPrior參數 */
        'onPriorCallback': function(timeout, seconds){
	  		timeout.options.extendOnMouseMove=false;
	  		timeout.mouseMoved = true;
	  		$("#timeoutModal").modal('show');	  			            
	  	},
	  	/* 滑鼠移動延長Session設定為False */
        'extendOnMouseMove': false,
	  	/* 時間到會觸發的url */
        'onTimeout': function(timeout){
			/* Force logout */
	  		window.location.href="logout_url";
	  	}
	});
    var timer,	
    setTimer = function(){
	  	timer = window.setInterval(function(){
	  		$('#curTime').val( window.localStorage.timeoutCountdown );
	  		$('#consTime').text( window.localStorage.timeoutCountdown );
	  	}, 1000);
	};
    setTimer();
});
</script>

需要根據環境客製化的有

  • your_js_path
  • logout_url

    延伸Server的Session與頁面Timeout Reset

    <script>
    function reset(){
     $.jTimeout.reset();
     var URL = "Server_Session_Extend_Url";		   
      	$.ajax({
      		type : 'POST',
      		url: URL,
      		success: function (resp) {
      			$.jTimeout.reset();
      		}
      	});
    }                        
    </script>
    

    需要根據環境客製化的有

  • Server_Session_Extend_Url

    頁面跳出的Modal倒數60秒後會自動登出,可點選延長Session或直接登出

<div class="modal fade" id="timeoutModal" role="dialog">
    <div class="modal-dialog">
        <!-- Modal content-->
        <div class="modal-content">
            <div class="modal-header" style="text-align: center;">
                <h4 class="modal-title">閒置時間過久</h4>
            </div>
            <div class="modal-body" style="text-align: center;">
                <label>距離系統強制登出剩餘</label> <label id='consTime'></label><label></label>
            </div>
            <div class="modal-footer" style="text-align: center;">
                <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="reset();">
                    延長
                </button>
                <a href="logout_url">
					登出
				</a>
            </div>
        </div>
    </div>
</div>

需要根據環境客製化的有

  • logout_url

jTimeout.js

/*
 *
 *
 jTimeout v2.1
 Made with love by Versatility Werks (http://flwebsites.biz)
 MIT Licensed
 *
 *
 */
(function ($) {

    $.jTimeout = function (options) {

        if( typeof window.jTimeout !== 'undefined' )
        {
            return window.jTimeout;
        }

        options = $.extend({}, $.jTimeout.defaults, options);

        var timeout =
        {
            /**
             * Whether or not the session has timed out
             */
            timedOut: false,
            /**
             * Whether or not there is currently a timeout warning on the screen
             */
            timeoutWarning: false,
            /**
             * The interval loop for counting down
             */
            interval: false,
            /**
             * The settimeout for mouse movement to be debounced
             */
            mouseTimeout: false,

            options: options,

            /**
             * Generates a random ID to identify the current tab
             * 
             * @param separator
             * @returns {*}
             */
            generateUid: function(separator)
            {
                var delim = separator || "-";

                return (this.S4() + this.S4() + delim + this.S4() + delim + this.S4() + delim + this.S4() + delim + this.S4() + this.S4() + this.S4());
            },
            S4: function()
            {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
            },
            get: function(key)
            {
                return window.localStorage.getItem(key);
            },
            set: function(key, val)
            {
                return window.localStorage.setItem(key, val);
            },
            /**
             * Gets the current time left
             */
            getTimer: function()
            {
                return this.get('timeoutCountdown');
            },
            /**
             * Sets the time left
             *
             * @param curTime
             */
            setTimer: function(curTime)
            {
                return this.set('timeoutCountdown', curTime);
            },
            /**
             * Gets the tab that is controlling the timeout countdown
             */
            getTab: function()
            {
                return this.get('timeoutTab');
            },
            /**
             * Sets the tab that is controlling the timeout countdown
             * @param tab
             */
            setTab: function(tab)
            {
                return this.set('timeoutTab', tab);
            },
            /**
             * Gets the last tab that updated the timer countdown
             */
            getTabLast: function()
            {
                return this.get('timeoutTabLast');
            },
            /**
             * Sets the last tab that updated the timer countdown
             */
            setTabLast: function()
            {
                return this.set('timeoutTabLast', new Date());
            },
            /**
             * Stops the countdown prior to timeout
             */
            stopPriorCountdown: function()
            {
                if (timeout.priorCountDown)
                {
                    timeout.priorCountDown = false;
                }
            },
            /**
             * Determines whether or not the timeout countdown alert should allow extending the session and then hiding the alert
             *
             * @returns {*}
             */
            resetOnAlert: function()
            {
                if (!timeout.options.triggerResetOnAlert)
                {
                    return $('#jTimeoutAlert').length === 0 && $('#jTimedoutAlert').length === 0;
                }

                return $('#jTimedoutAlert').length === 0 && timeout.options.triggerResetOnAlert;
            },
            /**
             * Stops flashing in the title
             */
            stopFlashing: function()
            {
                if (timeout.options.flashTitle)
                {
                    if (timeout.flashingTitle)
                    {
                        window.clearInterval(timeout.flashingTitle);
                    }

                    timeout.flashingTitle = false;

                    document.title = timeout.options.originalTitle;
                }
            },
            /**
             * Starts flashing the title
             */
            startFlashing: function()
            {
                if (!timeout.flashingTitle && timeout.options.flashTitle)
                {
                    timeout.flashingTitle = window.setInterval(function ()
                    {
                        if (document.title === timeout.options.flashingTitleText)
                        {
                            document.title = timeout.options.originalTitle;
                        }
                        else
                        {
                            document.title = timeout.options.flashingTitleText;
                        }
                    }, timeout.options.flashTitleSpeed);
                }
            },
            /**
             * Starts the countdown prior to timeout
             *
             * @param elem
             */
            startPriorCountdown: function(elem)
            {
                timeout.priorCountDown = elem;
            },
            /**
             * Hides the countdown alert
             */
            hideCountdownAlert: function()
            {
                timeout.timeoutWarning = false;

                var timeoutAlert = $('#jTimeoutAlert');

                if (timeoutAlert.length > 0)
                {
                    timeoutAlert.closeAlert();
                }
            },
            setMouseTimeout: function(timeout)
            {
                this.mouseTimeout = timeout;
            },
            stopMouseTimeout: function(){
                if( this.mouseTimeout)
                {
                    window.clearTimeout(this.mouseTimeout);
                }
            },
            setCountdown: function(interval){
                this.interval = interval;
            },
            stopCountdown: function()
            {
                if( this.interval )
                {
                    window.clearInterval(this.interval);
                }
            },
            /* The magic happens here. This function loops every x seconds */
            countdown: function()
            {
                /* Get current timer, tab that reported that time, and the time that tab reported */
                var seconds = timeout.getTimer(),
                    whichTab = timeout.getTab(),
                    whichTabLast = timeout.getTabLast();

                /* If another tab updated it more than 2 seconds ago, this tab will take control */
                if (whichTabLast < new Date('-2 seconds'))
                {
                    seconds = seconds - Math.abs(((new Date()).getTime() - whichTabLast.getTime()) / 1000); //remove difference
                    whichTab = timeout.options.tabID;
                    timeout.setTab(whichTab);
                }

                if (timeout.priorCountDown)
                {
                    timeout.priorCountDown.text(seconds);
                }

                /* If the last tab to interact is the same as this one */
                if (whichTab === timeout.options.tabID)
                {
                    seconds = seconds - timeout.options.heartbeat;
                    timeout.setTabLast();
                    timeout.setTimer(seconds);
                }

                /* Timeout */
                if (seconds <= 0 && !timeout.timedOut)
                {
                    timeout.timeoutWarning = true;
                    timeout.timedOut = true;

                    timeout.options.onTimeout(timeout);

                    timeout.stopCountdown();

                    timeout.stopMouseTimeout();

                    timeout.setTimer(0);
                }
                /* If less than x seconds left and not warned yet, show warning */
                else if (seconds < timeout.options.secondsPrior && !timeout.timeoutWarning)
                {
                    timeout.timeoutWarning = true;

                    timeout.startFlashing();

                    timeout.options.onPriorCallback(timeout, seconds);

                }
                /* reset timeout warning if timeout was set higher */
                else if (seconds >= timeout.options.secondsPrior && timeout.timeoutWarning)
                {
                    timeout.stopFlashing();
                    timeout.stopPriorCountdown();
                    timeout.hideCountdownAlert();
                }
            }
        };

        //if no tab id was provided, generate a unique tab id
        if (!timeout.options.tabID)
        {
            timeout.options.tabID = timeout.generateUid();
        }

        /* Set defaults in localStorage (shared storage across tabs) */
        timeout.setTimer(timeout.options.timeoutAfter);
        timeout.setTab(timeout.options.tabID);
        timeout.setTabLast();

        var inMS = timeout.options.heartbeat * 1000;

        timeout.setCountdown(window.setInterval(timeout.countdown, inMS));

        if(timeout.options.extendOnMouseMove)
        {
            inMS = timeout.options.mouseDebounce * 1000;

            timeout.mouseMoved = false;

            //delay the initial mousemove watch for x seconds
            timeout.setMouseTimeout(window.setTimeout(function ()
            {
                //on mouse move
                $('body').on('mousemove', function ()
                {
                    if (!timeout.mouseMoved && timeout.resetOnAlert())
                    {
                        timeout.mouseMoved = true;

                        timeout.setMouseTimeout(window.setTimeout(function ()
                        {
                            timeout.mouseMoved = false;
                        }, inMS));

                        timeout.options.onMouseMove(timeout);
                    }
                });

            }, inMS));
        }

        window.jTimeout = timeout;

        return timeout;
    };

    $.jTimeout.reset = function (seconds)
    {
        seconds = typeof seconds !== 'undefined' ? seconds : $.jTimeout.defaults.timeoutAfter; //default to default timeoutAfter

        $.jTimeout().set('timeoutCountdown', seconds); //set timeout countdown
    };

    $.jTimeout.defaults = {
        'flashTitle': true, //whether or not to flash the tab/title bar when about to timeout, or after timing out
        'flashTitleSpeed': 500, //how quickly to switch between the original title, and the warning text
        'flashingTitleText': '**WARNING**', //what to show in the tab/title bar when about to timeout, or after timing out
        'originalTitle': document.title, //store the original title of this page

        'tabID': false, //each tab needs a unique ID so you can tell which one last updated the timer - false makes it autogenerate one
        'timeoutAfter': 600, //pass this from server side to be fully-dynamic. For PHP: ini_get('session.gc_maxlifetime'); - 1440 is generally the default timeout
        'heartbeat': 1, //how many seconds in between checking and updating the timer

        'extendOnMouseMove': true, //Whether or not to extend the session when the mouse is moved
        'mouseDebounce': 30, //How many seconds between extending the session when the mouse is moved (instead of extending a billion times within 5 seconds)
        'onMouseMove': function(timeout){
            //request the session extend page
            //$.get(timeout.options.extendUrl);
        	//console.log("extend");
            //reset timer
            timeout.setTimer(timeout.options.timeoutAfter);
            //set cur tab to this one
            timeout.setTab(timeout.options.tabID);
            timeout.setTabLast();
        }, //Override the standard $.get() request that uses the extendUrl with your own function.

        'extendUrl': '/dashboard', //URL to request in order to extend the session.
        'logoutUrl': '/', //URL to request in order to force a logout after the timeout. This way you can end a session early based on a shorter timeout OR if the front-end timeout doesn't sync with the backend one perfectly, you don't look like an idiot.
        'loginUrl': '/login', //URL to send a customer when they want to log back in

        'secondsPrior': 60, //how many seconds before timing out to run the next callback (onPriorCallback)

        'triggerResetOnAlert': false, // should it reset the timer with mouse move while the alert is visible and hide it?

        //override the popup that shows when getting within x seconds of timing out
        'onPriorCallback': function(timeout, seconds){        	
            console.log("onPriorCallback");
            timeout.options.extendOnMouseMove=false;
            timeout.mouseMoved = true;
            //$("#myModal").modal('show');
        },
        //override the click to extend button callback
        'onClickExtend': function(timeout){
            /* Request dashboard to increase session */
            //$.get(timeout.options.extendUrl);
        	//console.log("extend");
            timeout.setTimer(timeout.options.timeoutAfter);
            timeout.setTab(timeout.options.tabID);
            timeout.setTabLast();
        },
        //override the timeout function if you'd like
        'onTimeout': function(timeout){
            /* Alert User */
            console.log('timeout');

            /* Force logout */
            $.get(timeout.options.logoutUrl);
        }
    };

    /* END OF ON JQUERY LOAD */
})(jQuery);





Search

    Post Directory