开发者

JSP Automatic Redirect After Session Expire/Timeout

开发者 https://www.devze.com 2023-01-19 12:54 出处:网络
Is there any way to detect session timeout without (user interaction)*, and redirect it to some page; i.e. if there is no activity on page @ specific duration; server detects it and redirect it automa

Is there any way to detect session timeout without (user interaction)*, and redirect it to some page; i.e. if there is no activity on page @ specific duration; server detects it and redirect it automatically on some other.

By user user interaction I mean; there is a way to detect session timeout when user clicks on something, then some request goes to 开发者_如何学Pythonserver and then server checks if current user session is expired or not.

What I need here is that we don't inform server anything (or we don't perform any action), but when session expires server detects it automatically and perform required action.

Thanks, Raza


If the requirement is to just redirect to the login page (or any other page) after the session timed out, this is how I've tried to implement it:

Include the following scriptlet to ALL pages that requires login

<%
int timeout = session.getMaxInactiveInterval();
response.setHeader("Refresh", timeout + "; URL = login.jsp");
%>

This way any page that requires login will refresh/redirect to login.jsp (change it your desired url) after the session timed out

OR (to avoid missing any pages)

You can actually write it in a separate file (timedoutRedirect.jsp) and include it as a header to all pages that requires login using "JSP property group" (in web.xml)

<jsp-property-group>
        <display-name>all jsp</display-name>
        <url-pattern>/users/*</url-pattern>
        <include-prelude>/timedoutRedirect.jsp</include-prelude>           
</jsp-property-group>

(you may have to adjust the prelude url to your project specifications)


You can of course do such a thing in JavaScript by implementing a document-wide keyboard and / or mouse listener and a periodical method with a timeout.

var timeOut = 1000 * 60 * 30; // 30 minutes
var lastActivity = new Date().getTime();
var checkTimeout;
checkTimeOut = function(){
    if(new Date().getTime() > lastActivity + timeOut){
        // redirect to timeout page
    }else{
        window.setTimeout(checkTimeOut, 1000); // check once per second
    }
}

now your global listeners just have to set lastActivity to the current time on every action.

On re-reading the question, you want to use the actual session timeout from the application server. That's a tough one, because your when you send ajax requests to the server you will actually keep the session from expiring (unless there is a hard limit), so my answer might still be the best way to do it.


I had somewhat of the same problem so here's how I solved it...

Basically I created a session timer on the client side with javascript. I send an ajax call periodically (on a timer that is less than the actual server timeout setting) to keep the session alive on the server.

Then I created another timer that counts down on the client side (set to the same time as the actual server timeout setting). If that timer expires, then an ajax call is made to the server that runs session.invalidate() and then forwards to the login page. This timer is reset every time there is some action that should keep the session alive (i.e. mouse click, keypress, etc.)


Either it may be simple servlet, spring-mvc or spring-security auto logout is not possible without perfect client side logic.
Considering application will have both type of request

  • AJAX and
  • form submission/page reload

Auto logout needs very calculated logic. Presenting my autologout functionality implementation with following

Advantages.


1. No extra call/request is used to achieve this. considering performance impact if more than 10k active users and extra calls to achieve auto logout.
2. One line configuration using tag.
3. Works flawlessly even if user opens multiple tab or multiple window.
4. It intimates you before 30 seconds of session invalidation, so if you have filled form and not submitted, you can keep session alive(extend session by one click). So user less likely to loose unsaved data.

Usage


1. Include auto logout script in required JSP pages as given below.

    ....
    </body>
    <jsp:include page="../template/autologout-script.jsp"></jsp:include>
</html>

2. Create a JSP page, autologout-script.jsp and add below code. Note: No editing/configuring is required

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<script>
$(document).ready(function()
{
    var timeOutTimeInSeconds = ${ timeOutTimeInSeconds }; 
    var showTimerTimeInSeconds= ${ showTimerTimeInSeconds };

    var sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);
    var timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);
    var badgeTimerId;
    window.localStorage.setItem("AjaxRequestFired", new Date());

    function redirectToLoginPage(){
        //location.href =  '<c:url value="/" />'+'${loginPageUrl}';
        window.location.reload();
    }

    $(document).ajaxComplete(function () {
        resetTimer();
    });

    $(window).bind('storage', function (e) {
         if(e.originalEvent.key == "AjaxRequestFired"){
             console.log("Request sent from another tab, hence resetting timer")
             resetTimer();
         }
    });

    function resetTimer()
    {
        showTimerTimeInSeconds= ${ showTimerTimeInSeconds };

        console.log("timeOutTimeInSeconds : "+timeOutTimeInSeconds)
        window.localStorage.setItem("AjaxRequestFired", new Date());

        window.clearInterval(sessionCheckIntervalId);
        sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);

        window.clearInterval(timerDisplayIntervalId);
        timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);

        hideTimer();
    }

    function showTimer()
    {
        $('#sessionTimeRemaining').show();
        $('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
        window.clearInterval(timerDisplayIntervalId);
        badgeTimerId = setInterval(function(){
            $('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
        }, 1000);
    }

    function hideTimer()
    {
        window.clearInterval(badgeTimerId);
        $('#sessionTimeRemaining').hide();
    }
});
</script>

3. Configure session attributes to configuring timeout setting Note: Configure this after session creation. You can implement HttpSessionListener sessionCreated method and set the following configuration as per your requirement.

session.setMaxInactiveInterval(300);

session.setAttribute("timeOutTimeInSeconds", 300);
session.setAttribute("showTimerTimeInSeconds", 30);

4. Add below html for displaying timer.
Note: it can be moved to autologout-script template page if you are good at CSS. Hence you can avoid to add this in each and every page.
Include bootstrap or add your custom css.

<span class="badge badge-primary" title="click to keep session alive" id="sessionTimeRemaining" 
    onclick="ajaxSessionRefresh()" style="display:none;">
    <i class="badge badge-danger" id="sessionTimeRemainingBadge" style="float:left">30</i>
     &nbsp; 
     <small>Refresh</small>
     <i class="glyphicon glyphicon-refresh"></i>
</span>

JSP Automatic Redirect After Session Expire/Timeout

That is all about a simple auto logout implementation. You can download working example from my github repository
Autologout using simple servlet example
Autologout using spring-security java configuration example
Autologout using spring-security xml configuration example

Logic Explained


Case 1: On Page load
Here logic is simple, on page load set timer of interval equlas to maxInactiveInterval. after timeout redirect to login page.
Case 2: Keep track AJAX calls
Now considering AJAX requests, you can use .ajaxStart() or .ajaxComplete() callbacks of jquery so that if any ajax request is fired you can reset the interval.
Case 3: Tracking multi tab/window activity
Intertab communication is done to synchronize state of each tab. Used localStorage on change event.

Limitations/Improvements required
1. If maximum allowed session is one, if session is taken from another system, AJAX request will fail. It needs to be handled to redirect to login page.
2. Use ajaxStart() instead of ajaxComplete() to have exact sync of idleTime values between server and browser.

Requirements
1. Jquery

Alternatives to current implementation compared


1. Setting Refresh header in http response. (Not works for AJAX requests)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. Setting meta refresh tag in HTML (Not works for AJAX requests)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. Configuring Activity checker Keeps session alive by repeated AJAX request. Tracks idle time and makes logout request after timeout.
    No doubt it is a good one with simple logic. But i want to just ink my observations.
    • Performance impact if 2 requests are made per minute to keep session alive and 50k active users. 100k requests per minute.
    • Intertab communication If two tabs are open, one tab is receiving activity but other tab is not receiving activity, that tab fires logout request and invalidate session even though activity is present in other tab. (But can be handled)
    • Force logout approach It is a client is dominated over server to invalidate session.
0

精彩评论

暂无评论...
验证码 换一张
取 消